首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何停止goroutine

如何停止goroutine
EN

Stack Overflow用户
提问于 2017-03-01 03:00:39
回答 3查看 4.6K关注 0票数 4

我有一个goroutine,它调用一个函数,并使用一个特殊的参数来启动或停止这个goroutine。我的问题是,这段代码从来不会停止我的goroutine,它会在每次新作业时创建。

代码语言:javascript
复制
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
    }

我如何停止我的例程?

EN

回答 3

Stack Overflow用户

发布于 2017-03-01 03:08:09

当您关闭run通道时,case <-run将始终触发:在关闭的通道上侦听将立即返回零值。

如果你想停止goroutine,你应该在收到<-quit信号后返回。

顺便说一句,你的default:子句让for循环积极地工作,你应该去掉它(你仍然会在两个通道上监听)

票数 1
EN

Stack Overflow用户

发布于 2017-03-01 03:22:03

下面是一个孤立的、带注释的、可运行的版本,说明如何实现这样的信令系统。

代码语言:javascript
复制
package main

import (
    "time"
    "log"
)

func main() {
    statusChannel := make(chan bool)
    go applicationLoop(statusChannel)

    // reasonably random outcome for testing
    if time.Now().Unix() % 2 == 0 {
        statusChannel<-true
    } else {
        statusChannel<-false
    }

    for {
        // busy loop for testing
        time.Sleep(1000)
    }
}

func applicationLoop(statusChannel chan bool) {
    defer close(statusChannel)
    for {
        log.Printf("waiting for signal...\n")
        shouldContinue := <-statusChannel
        if !shouldContinue {
            log.Print("received false, breaking...\n")
            break
        }
        // run your code here
        // you should use a second channel to return results, as the channel is not buffered
        log.Print("working...\n")
    }
}

请注意,向statusChannel发送一个值,而不是侦听一个值,这将使示例在您的面前爆炸。要么使用缓冲通道,要么使用在goroutine重新侦听信号时向main发回信号的通道。

票数 1
EN

Stack Overflow用户

发布于 2017-03-01 05:15:35

这个问题有两个部分。

首先,我们需要以某种方式停止子goroutines,即使父goroutines停止,它的所有子进程也应该得到通知并停止--一个向下但不向上的停止信号的层次结构。

另一方面,父母需要等待它的孩子,直到他们完成。否则,我们将从goroutine返回,甚至在某些goroutine正确完成之前退出应用程序。

为了简单起见,我们忽略了实现错误处理、超时等。

为了处理第一个问题,我们使用了context.Context,它为我们提供了一个很好的执行上下文处理工具的层次结构;为了解决第二个问题,我们使用了sync.WaitGroup,它允许我们等待一组goroutines来完成它们的任务。一个简单的演示是:

代码语言:javascript
复制
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`)
        }
    }
}

这给了我们一些输出,比如:

代码语言:javascript
复制
[  info ] level2
[  info ] level2
[  info ] level2
[  info ] level1
[  info ] level2
[  info ] level1
[  info ] level2
[  info ] level2

目前还没有提供结合context.Contextsync.WaitGroup功能的官方包。最近的东西是一个errgroup,它可以通过一些hack类似于这个功能。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42516717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档