英文:
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)
}
英文:
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 (
"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)
}
答案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 channel
s 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 (
"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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论