如何停止goroutine [英] How to stop goroutine
问题描述
我有一个goroutine调用一个函数,并且有一个特殊的参数,我想要启动或停止这个goroutine。我的问题是这段代码永远不会停止我的goroutine,它每创建一项新工作都会创建。
quit:= make(chan bool)
run:= make(chan bool)
go func(){
for {
select {
case< -quit:
close(run)
case< -run:$ b $如果x == true {
quit< - b myFunc(c)
default:
}
}
}()
true
} else {
run< - true
}
我如何停止我的日常工作?
这个问题有两个部分。
首先,我们需要以某种方式停止子例程,即使父例程停止,它的所有子程序都应该得到通知并停止 - 停止信号的层次结构但没有。
另一方面,父母需要等待它的孩子,直到他们完成。否则,我们会从goroutine返回,甚至在某些goroutine正常完成之前退出应用程序。
为简单起见,我们忽略实现错误处理,超时等。 p>
为了处理第一个问题,我们使用 context.Context
,它给了我们一个很好的执行上下文处理工具和解决方案第二个问题是我们使用 sync.WaitGroup
,这允许我们等待一组goroutines来完成他们的任务。一个简单的示例是:
$ b $ pre $ func main(){
all:=& sync.WaitGroup {}
rootCtx,rootCancel:= context.WithCancel(context.Background())
all.Add(1)
go level1(rootCtx,全部)
//只是为了模拟停止,我们可以使用os信号来代替
// app在3秒后结束
去func(){
time.Sleep(time.Second * 3)
rootCancel()
}()
all.Wait()
}
func level1(parent context.Context,all * sync .WaitGroup){
defer all.Done()
l1Ctx,l1Cancel:= context.WithCancel(parent)
defer l1Cancel()
for i:= 0 ;我< 3; i ++ {
all.Add(1)
去等级2(l1Ctx,全部)
}
用于{
选择{
case< ; -parent.Done():
返回
//其他情况下,如果有的话,
//这是一个样例
case< -time.After(time.Second) :
log.Println(`level1`)
}
}
}
$ b func level2(parent context.Context,all * sync.WaitGroup) {
defer all.Done()
for {
select {
case< -parent.Done():
return
case< - time.After(time.Second):
log.Println(`level2`)
}
}
}
这给了我们一些输出:
[info] level2
[info] level2
[info] level2
[info] level1
[info] level2
[info] level1
[info] level2
[info] level2
目前是不提供结合 context.Context
和 sync.WaitGroup
的功能的官方软件包。最近的是 errgroup
,它可以通过一些黑客来类似这个功能。
I have a goroutine that calls a function and with a special parameter i want to start or stop this goroutine. My problem is that this code never stops my goroutine, it creates everytime a new job.
quit := make(chan bool)
run := make(chan bool)
go func() {
for {
select {
case <-quit:
close(run)
case <-run:
myFunc(c)
default:
}
}
}()
if x == true {
quit <- true
} else {
run <- true
}
How do I stop my routine?
This problem has two parts.
First we need to stop child goroutines somehow in a way that even if a parent goroutines stops, all it's children should get notified and stop - a hierarchy of stop signals that goes down but not up.
On the other hand the parent needs to wait for it's children until they are done. Otherwise we would return from a goroutine or even exit from the app before some goroutines are finished properly.
For simplicity we ignore implementing error handling, timeouts and the like.
For handling the first problem we use context.Context
which gives us a nice hierarchy of execution context handling tools and for solving the second problem we use sync.WaitGroup
which allows us to wait for a group of goroutines to complete their tasks. A simple demonstration would be:
func main() {
all := &sync.WaitGroup{}
rootCtx, rootCancel := context.WithCancel(context.Background())
all.Add(1)
go level1(rootCtx, all)
// just to simulate stop, we could use an os signal instead
// app ends after 3 seconds
go func() {
time.Sleep(time.Second * 3)
rootCancel()
}()
all.Wait()
}
func level1(parent context.Context, all *sync.WaitGroup) {
defer all.Done()
l1Ctx, l1Cancel := context.WithCancel(parent)
defer l1Cancel()
for i := 0; i < 3; i++ {
all.Add(1)
go level2(l1Ctx, all)
}
for {
select {
case <-parent.Done():
return
// other cases if any,
// this is a sample
case <-time.After(time.Second):
log.Println(`level1`)
}
}
}
func level2(parent context.Context, all *sync.WaitGroup) {
defer all.Done()
for {
select {
case <-parent.Done():
return
case <-time.After(time.Second):
log.Println(`level2`)
}
}
}
Which gives us some output like:
[ info ] level2
[ info ] level2
[ info ] level2
[ info ] level1
[ info ] level2
[ info ] level1
[ info ] level2
[ info ] level2
Currently there is no official package that provide a functionality which combines context.Context
and sync.WaitGroup
. The nearest thing is an errgroup
which can resemble this functionality with some hacks.
这篇关于如何停止goroutine的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!