如何使用Go协程和Term UI退出我的Go代码

huangapple go评论98阅读模式
英文:

How to exit from my go code using go routines and term ui

问题

我最近开始学习Go语言,对其所有的特性印象深刻。我一直在使用Go协程和term-ui,并遇到了一些问题。我试图在运行代码后从控制台退出,但它没有响应。如果我不使用Go协程,它会响应我的"q"键按下事件。

希望能得到帮助。

我的代码:

package main

import (
	"fmt"
	"github.com/gizak/termui"
	"time"
	"strconv"
)

func getData(ch chan string) {
	i := 0
	for {
		ch <- strconv.Itoa(i)
		i++
		time.Sleep(time.Second)
		if i == 20 {
			break
		}
	}
}

func Display(ch chan string) {
	err := termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		fmt.Println("q captured")
		termui.Close()
		termui.StopLoop()
	})

	for elem := range ch {
		par := termui.NewPar(elem)
		par.Height = 5
		par.Width = 37
		par.Y = 4
		par.BorderLabel = "term ui example with chan"
		par.BorderFg = termui.ColorYellow
		termui.Render(par)
	}
}

func main() {
	ch := make(chan string)
	go getData(ch)
	Display(ch)
}

term-ui是一个很好的Go语言库,你可以在这里找到它。

英文:

I recently started learning go and I am really impressed with all the features. I been playing with go routines and term-ui and facing some trouble. I am trying to exit this code from console after I run it but it just doesn't respond. If I run it without go-routine it does respond to my q key press event.

Any help is appreciated.

My code

package main

import (
    &quot;fmt&quot;
    &quot;github.com/gizak/termui&quot;
    &quot;time&quot;
    &quot;strconv&quot;
)

func getData(ch chan string) {
  i := 0
  for {
	ch &lt;- strconv.Itoa(i)
	i++
	time.Sleep(time.Second)
	if i == 20 {
		break
    }
  }
}

func Display(ch chan string) {
  err := termui.Init()
  if err != nil {
	panic(err)
  }
  defer termui.Close()
  termui.Handle(&quot;/sys/kbd/q&quot;, func(termui.Event) {
	fmt.Println(&quot;q captured&quot;)
	termui.Close()
	termui.StopLoop()
  })

  for elem := range ch {
	par := termui.NewPar(elem)
	par.Height = 5
	par.Width = 37
	par.Y = 4
	par.BorderLabel = &quot;term ui example with chan&quot;
	par.BorderFg = termui.ColorYellow
	termui.Render(par)
  }
}

func main() {
  ch := make(chan string)
  go getData(ch)
  Display(ch)
}

答案1

得分: 1

这可能是你要找的答案。首先,你没有正确使用termui。你需要调用它的Loop函数来启动Event循环,以便它可以开始监听q键。Loop函数是最后调用的,因为它从那时起实际上控制了主goroutine,直到调用StopLoop并退出。

为了停止goroutine,通常会有一个“stop”通道。通常它是一个chan struct{},以节省内存,因为你不需要在其中放任何东西。无论你想在哪里可能停止和关闭goroutine(或者做其他事情),你都可以使用带有你正在使用的通道的select语句。这个select是有序的,所以它会按顺序从中取出,除非它们阻塞,在这种情况下它会尝试下一个,所以stop通道通常放在第一位。stop通道通常会阻塞,但是要让它选择这个路径,只需close()它就会选择这个路径。所以我们在q键盘处理程序中close()它。

package main

import (
	"fmt"
	"github.com/gizak/termui"
	"strconv"
	"time"
)

func getData(ch chan string, stop chan struct{}) {
	i := 0
	for {
		select {
		case <-stop:
			break
		case ch <- strconv.Itoa(i):
		}
		i++
		time.Sleep(time.Second)
		if i == 20 {
			break
		}
	}
}

func Display(ch chan string, stop chan struct{}) {

	for {
		var elem string
		select {
		case <-stop:
			break
		case elem = <-ch:
		}
		par := termui.NewPar(elem)
		par.Height = 5
		par.Width = 37
		par.Y = 4
		par.BorderLabel = "term ui example with chan"
		par.BorderFg = termui.ColorYellow
		termui.Render(par)
	}
}

func main() {
	ch := make(chan string)
	stop := make(chan struct{})
	err := termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		fmt.Println("q captured")
		close(stop)
		termui.StopLoop()
	})
	go getData(ch, stop)
	go Display(ch, stop)
	termui.Loop()
}
英文:

This is possibly the answer you are looking for. First off, you aren't using termui correctly. You need to call it's Loop function to start the Event loop so that it can actually start listening for the q key. Loop is called last because it essentially takes control of the main goroutine from then on until StopLoop is called and it quits.

In order to stop the goroutines, it is common to have a "stop" channel. Usually it is a chan struct{} to save memory because you don't ever have to put anything in it. Wherever you want the goroutine to possibly stop and shutoff (or do something else perhaps), you use a select statement with the channels you are using. This select is ordered, so it will take from them in order unless they block, in which case it tries the next one, so the stop channel usually goes first. The stop channel normally blocks, but to get it to take this path, simply close()ing it will cause this path to be chosen in the select. So we close() it in the q keyboard handler.

package main
import (
&quot;fmt&quot;
&quot;github.com/gizak/termui&quot;
&quot;strconv&quot;
&quot;time&quot;
)
func getData(ch chan string, stop chan struct{}) {
i := 0
for {
select {
case &lt;-stop:
break
case ch &lt;- strconv.Itoa(i):
}
i++
time.Sleep(time.Second)
if i == 20 {
break
}
}
}
func Display(ch chan string, stop chan struct{}) {
for {
var elem string
select {
case &lt;-stop:
break
case elem = &lt;-ch:
}
par := termui.NewPar(elem)
par.Height = 5
par.Width = 37
par.Y = 4
par.BorderLabel = &quot;term ui example with chan&quot;
par.BorderFg = termui.ColorYellow
termui.Render(par)
}
}
func main() {
ch := make(chan string)
stop := make(chan struct{})
err := termui.Init()
if err != nil {
panic(err)
}
defer termui.Close()
termui.Handle(&quot;/sys/kbd/q&quot;, func(termui.Event) {
fmt.Println(&quot;q captured&quot;)
close(stop)
termui.StopLoop()
})
go getData(ch, stop)
go Display(ch, stop)
termui.Loop()
}

huangapple
  • 本文由 发表于 2017年7月27日 02:57:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/45335327.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定