英文:
How do I kill a goroutine
问题
我有以下的设置:
func startsMain (){
go main ()
}
fun stopMain (){
//kill main
}
func main() {
//无限循环
}
我正在创建黄瓜步骤,我需要能够启动和关闭应用程序。
英文:
I have the following setup:
func startsMain (){
go main ()
}
fun stopMain (){
//kill main
}
func main() {
//infinite loop
}
I am creating cucumber steps and I need to be able to start and shut down the application.
答案1
得分: 6
你可以使用select
和通道来终止无限循环!
var quit chan struct{}
func startLoop() {
quit := make(chan struct{})
go loop()
}
func stopLoop() {
// 如Kaedys所提到的
//close(quit)
// 允许一次性停止所有具有`case <-quit:`语句的信号,这可能更好。
quit <- struct{}{}
}
// 顺便说一下,你不能将函数命名为main,它是保留的
func loop() {
for {
select {
case <-quit:
return // 比break更好
default:
// 做一些事情。为了清晰起见,我会调用一个函数:
do_stuff()
}
}
}
不错的Go交换代码,不是吗?
那么,这个奇怪的chan struct{}
是什么?它是一个零大小的通道。我们只能用空结构体(即struct{}{}
)填充它。它可以是chan bool
或其他任何类型,因为我们不使用通道的内容。重要的是,我们使用quit
通道来通知我们的goroutine中的无限循环停止的时间。
select
语句用于捕获通道中的内容。它是一个阻塞语句(它将暂停执行,直到某个通道中有内容被放入被case
监视的通道中),除非你加入一个default
语句。在这种情况下,每次执行select
时,如果在quit
中放入了内容,循环将中断,否则将调用do_stuff()
。如果你已经完成了Go Tour,你已经知道这一点。
其他很酷的并发模式可以在Go Blog上找到。
最后,为了更有趣,你可以使用Ticker
来定时执行do_stuff
函数,而不是占用100%的CPU,像这样:
import "time"
// [...]
func loop() {
// 这个ticker每2秒向其通道中放入内容
ticker := time.NewTicker(2 * time.Second)
// 如果你不停止它,ticker会导致内存泄漏
defer ticker.Stop()
for {
select {
case <-quit:
return
case <-ticker.C:
// 做一些事情。为了清晰起见,我会调用一个函数:
do_stuff()
}
}
}
在这里,select
是阻塞的,因为我们删除了default
语句。
英文:
You can kill you infinite loop using select
and channels!
var quit chan struct{}
func startLoop() {
quit := make(chan struct{})
go loop()
}
func stopLoop() {
// As mentioned by Kaedys
//close(quit)
// permits signalling everyone havins such a `case <-quit:`
// statement to be stopped at once, which might be even better.
quit <- struct{}{}
}
// BTW, you cannot call your function main, it is reserved
func loop() {
for {
select {
case <-quit:
return # better than break
default:
// do stuff. I'd call a function, for clarity:
do_stuff()
}
}
}
Nice piece of Go swap, ain't it?
Now, what is this strange chan struct{}
? It is a zero-sized channel. We can only fill it with empty structs (that is: struct{}{}
). It could be a chan bool
or whatever else, since we don't use the content of the channel. The important point is that we use the quit
channel to notify the infinite loop in our goroutine that it is time to stop.
The select
statement is used to catch what comes out of channels. It is a blocking statement (that will halt the execution until something is put in one of the channels surveyed by a case
), unless you put a default
statement. In this situation, every time the select
is executed, the loop will break if something was put inside quit
, or do_stuff()
will be called. You already know this if you've been through the Go Tour.
Other cool concurrency patterns can be found on the Go Blog.
Finally, for further fun, you can ask your do_stuff
function to be executed at regular time intervals by using Ticker
s, instead of consuming 100% CPU, like so:
import "time"
// [...]
func loop() {
// This ticker will put something in its channel every 2s
ticker := time.NewTicker(2 * time.Second)
// If you don't stop it, the ticker will cause memory leaks
defer ticker.Stop()
for {
select {
case <-quit:
return
case <-ticker.C:
// do stuff. I'd call a function, for clarity:
do_stuff()
}
}
}
Here, select
is blocking, since we removed the default
statement.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论