如何向 goroutine 发送信号以停止运行?

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

How to signal to a goroutine to stop running?

问题

我正在尝试停止一个Go协程,但是我找不到实现这一目标的方法。我在考虑使用第二个通道,但是如果我从那个通道读取数据,它会被阻塞,对吗?下面是一段代码,希望能解释清楚我想要做的事情。

package main

import "fmt"
import "time"

func main() {

	var tooLate bool

	proCh := make(chan string)

	go func() {
		for {
			fmt.Println("working")
			// 如果太晚了,我们停止/返回
			if tooLate {
				fmt.Println("stopped")
				return
			}
			// 处理一些数据并将结果发送到proCh通道
			time.Sleep(2 * time.Second)
			proCh <- "processed"
			fmt.Println("done here")

		}
	}()

	select {
	case proc := <-proCh:
		fmt.Println(proc)
	case <-time.After(1 * time.Second):
		// 以某种方式发送 tooLate <- true
		// 这样我们就可以停止运行的Go协程
		fmt.Println("too late")
	}

	time.Sleep(4 * time.Second)
	fmt.Println("finish\n")
}

在这里运行代码

英文:

I'm trying to stop a go routine but I can't find a way to achieve this. I was thinking to use a 2nd channel but if I read from that it would block it isn't it ?. Here is some code which I hope explains what I'm trying to do.

package main

import &quot;fmt&quot;
import &quot;time&quot;

func main() {

	var tooLate bool

	proCh := make(chan string)

	go func() {
		for {
		       fmt.Println(&quot;working&quot;)
		//if is tooLate we stop/return it
			if tooLate { 
			fmt.Println(&quot;stopped&quot;)
				return
			}
       //processing some data and send the result on proCh
			time.Sleep(2 * time.Second)
			proCh &lt;- &quot;processed&quot;
			fmt.Println(&quot;done here&quot;)

		}
	}()
	select {
	case proc := &lt;-proCh:
		fmt.Println(proc)
	case &lt;-time.After(1 * time.Second):
		// somehow send tooLate &lt;- true
		//so that we can stop the go routine running
		fmt.Println(&quot;too late&quot;)
	}
	
	time.Sleep(4 * time.Second)
	fmt.Println(&quot;finish\n&quot;)
}

Play this thing

答案1

得分: 2

有几种方法可以实现这个,最简单和最方便的方法是使用另一个通道,例如:

func main() {
    tooLate := make(chan struct{})
    proCh := make(chan string)

    go func() {
        for {
            fmt.Println("working")
            time.Sleep(1 * time.Second)
            select {
            case <-tooLate:
                fmt.Println("stopped")
                return
            case proCh <- "processed": //这就是为什么它不会阻塞goroutine,如果计时器过期。
            default: // 添加default将使其不阻塞
            }
            fmt.Println("done here")

        }
    }()
    select {
    case proc := <-proCh:
        fmt.Println(proc)
    case <-time.After(1 * time.Second):
        fmt.Println("too late")
        close(tooLate)
    }

    time.Sleep(4 * time.Second)
    fmt.Println("finish\n")
}

你也可以尝试使用 sync.Cond

英文:

There are few ways to achive that, the easiest and most convenient is using another channel like:

func main() {
	tooLate := make(chan struct{})
	proCh := make(chan string)

	go func() {
		for {
			fmt.Println(&quot;working&quot;)
			time.Sleep(1 * time.Second)
			select {
			case &lt;-tooLate:
				fmt.Println(&quot;stopped&quot;)
				return
			case proCh &lt;- &quot;processed&quot;: //this why it won&#39;t block the goroutine if the timer expirerd.
			default: // adding default will make it not block
			}
			fmt.Println(&quot;done here&quot;)

		}
	}()
	select {
	case proc := &lt;-proCh:
		fmt.Println(proc)
	case &lt;-time.After(1 * time.Second):
		fmt.Println(&quot;too late&quot;)
		close(tooLate)
	}

	time.Sleep(4 * time.Second)
	fmt.Println(&quot;finish\n&quot;)
}

<kbd>playground</kbd>

You can also look into using sync.Cond

huangapple
  • 本文由 发表于 2014年9月30日 21:27:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/26122072.html
匿名

发表评论

匿名网友

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

确定