用信号中断 Golang 中的无限循环
Interrupting an infinite loop in Golang with signals
我正在尝试制作一个使用信号来中断无限计数器循环的程序。我设法用 SIGINT (ctrl + C) 中断了程序,但我无法用其他方式中断它。我想知道我是否可以通过其他方式中断循环,例如在终端中 运行 时按下 Q 键。
我制作了两个 Go 文件,第一个包含实际的无限循环:
package infinite
import "fmt"
import "time"
func Infinite01 (msg string) {
for i := 0; ; i++ {
fmt.Println(msg, i)
time.Sleep(time.Second)
}
}
然后是捕获SIGINT信号并中断循环的文件:
package main
import (
"./infinite"
"os/signal"
"os"
"fmt"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt)
go func() {
<-sigs
fmt.Printf("You pressed ctrl + C. User interrupted infinite loop.")
os.Exit(0)
}()
Loop()
}
func Loop() {
infinite.Infinite01("Look, I can count forever:")
}
那么我会坚持我的第一条评论。我再解释一下。
您不需要信号来终止您的程序 - 您可以控制它。任何时候调用 os.Exit
都会退出程序,从 main()
调用 return 具有相同的效果。
相反,问题是何时触发这些 "exits"。或者,在您的示例中,如何在按下 key Q
时触发退出。
要解决这个问题,你需要把它分解成几个部分。正如我在评论中所说,第 1 部分正在捕获击键。它不像 fmt.Scan
那样简单,因为它需要用户在它之后按回车键。它需要一些 os 特定代码才能这样做,但希望一个库可以为您省去所有麻烦,例如 termbox-go.
part 2与part 1紧密相关,即指定事件,击键。在你的例子中,知道按下的键是Q,然后调用os.Exit
。通常一个库可以很容易地处理这个问题,有时人们几乎不会注意到其中的一部分。但是如果你想要一些更复杂的按键,比如 ctrl-alt-backspace
,甚至 a-s-d-f
(同时),这将需要一些代码。
第三部分是关于不阻塞程序的。在 Go 中,可以通过使用单独的 goroutine 来检查事件循环或使用古老的回调方式轻松实现。这取决于您选择的图书馆。
关于信号和 ctrl-c
案例的更多信息。通常的做法是 ctrl-c
必须在 most 种情况下向程序发送一个信号。如果未修改,则 sigint 会终止程序。但是,程序可以修改处理 sigint 的行为,就像您的原始代码一样(添加要打印的消息)。当按下其他键时,os不太可能将其绑定到另一个信号,因此您无法处理它。
当然,另一种解决方案是绑定一个 key compostion(多次击键)来向程序发送一个信号,但只要该程序本身就是接收击键的程序,那是一个冗余。
注意:由于库的选择可以多种多样,代码也有很大的不同,所以我认为我不能(或不应该)提供一个例子。
我正在尝试制作一个使用信号来中断无限计数器循环的程序。我设法用 SIGINT (ctrl + C) 中断了程序,但我无法用其他方式中断它。我想知道我是否可以通过其他方式中断循环,例如在终端中 运行 时按下 Q 键。
我制作了两个 Go 文件,第一个包含实际的无限循环:
package infinite
import "fmt"
import "time"
func Infinite01 (msg string) {
for i := 0; ; i++ {
fmt.Println(msg, i)
time.Sleep(time.Second)
}
}
然后是捕获SIGINT信号并中断循环的文件:
package main
import (
"./infinite"
"os/signal"
"os"
"fmt"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt)
go func() {
<-sigs
fmt.Printf("You pressed ctrl + C. User interrupted infinite loop.")
os.Exit(0)
}()
Loop()
}
func Loop() {
infinite.Infinite01("Look, I can count forever:")
}
那么我会坚持我的第一条评论。我再解释一下。
您不需要信号来终止您的程序 - 您可以控制它。任何时候调用 os.Exit
都会退出程序,从 main()
调用 return 具有相同的效果。
相反,问题是何时触发这些 "exits"。或者,在您的示例中,如何在按下 key Q
时触发退出。
要解决这个问题,你需要把它分解成几个部分。正如我在评论中所说,第 1 部分正在捕获击键。它不像 fmt.Scan
那样简单,因为它需要用户在它之后按回车键。它需要一些 os 特定代码才能这样做,但希望一个库可以为您省去所有麻烦,例如 termbox-go.
part 2与part 1紧密相关,即指定事件,击键。在你的例子中,知道按下的键是Q,然后调用os.Exit
。通常一个库可以很容易地处理这个问题,有时人们几乎不会注意到其中的一部分。但是如果你想要一些更复杂的按键,比如 ctrl-alt-backspace
,甚至 a-s-d-f
(同时),这将需要一些代码。
第三部分是关于不阻塞程序的。在 Go 中,可以通过使用单独的 goroutine 来检查事件循环或使用古老的回调方式轻松实现。这取决于您选择的图书馆。
关于信号和 ctrl-c
案例的更多信息。通常的做法是 ctrl-c
必须在 most 种情况下向程序发送一个信号。如果未修改,则 sigint 会终止程序。但是,程序可以修改处理 sigint 的行为,就像您的原始代码一样(添加要打印的消息)。当按下其他键时,os不太可能将其绑定到另一个信号,因此您无法处理它。
当然,另一种解决方案是绑定一个 key compostion(多次击键)来向程序发送一个信号,但只要该程序本身就是接收击键的程序,那是一个冗余。
注意:由于库的选择可以多种多样,代码也有很大的不同,所以我认为我不能(或不应该)提供一个例子。