如何终止一个 goroutine?

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

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 &lt;-quit:`
    // statement to be stopped at once, which might be even better.
    quit &lt;- struct{}{}
}

// BTW, you cannot call your function main, it is reserved
func loop() {
    for {
    	select {
    	case &lt;-quit:
    		return # better than break
    	default:
    		// do stuff. I&#39;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 Tickers, instead of consuming 100% CPU, like so:

import &quot;time&quot;

// [...]

func loop() {
	// This ticker will put something in its channel every 2s 
	ticker := time.NewTicker(2 * time.Second)
	// If you don&#39;t stop it, the ticker will cause memory leaks
	defer ticker.Stop()
    for {
    	select {
    	case &lt;-quit:
    		return
    	case &lt;-ticker.C:
    		// do stuff. I&#39;d call a function, for clarity:
    		do_stuff()
    	}
    }
}

Here, select is blocking, since we removed the default statement.

huangapple
  • 本文由 发表于 2017年3月2日 23:58:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/42560109.html
匿名

发表评论

匿名网友

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

确定