【问题标题】:How to stop one of multilpe of the same goroutine如何停止同一个goroutine的multilpe之一
【发布时间】:2019-08-10 07:38:05
【问题描述】:

很快就会明白,我是一个 golang n00b。

我有一些基于事件通道启动 goroutines 的 go 代码。假设它启动了 2 个 goroutine,因为我们收到了 2 个 START 类型的事件。

goroutine 以 uri 作为参数开始,这给了我们一些独特的东西。

稍后我们收到一个 STOP 类型的事件。

如何停止以相同 uri 启动的 goroutine?

for {
            select {
            case event := <-eventCh:
                if event.Entry != nil {
                    switch event.Action {
                    case foo.START:
                        log.Println("uri: ", event.Entry.URI)

                        go func(c chan []byte, u string) error{
                            //awesome goroutine code
                        }(myChan, event.Entry.URI)

                    case foo.STOP:
                        log.Println("uri: ", event.Entry.URI)
                        //I'd like to terminate the goroutine that matches event.Entry.URI
                    }
                }
            }
        }

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    你不能“从外部”停止一个 goroutine。您必须将某种取消信号传递给每个 goroutine 并记住它们以便稍后在主 goroutine 中使用。 Context 通常用作取消信号。然后 goroutine 必须检查取消并自愿退出:

    package main
    
    import (
        "context"
    )
    
    type Event struct {
        Action string
        URI    string
    }
    
    func main() {
        var eventCh chan Event
    
        ctx := context.Background()
    
        cancels := make(map[string]context.CancelFunc) // Maps URIs to cancellation functions.
    
        for event := range eventCh {
            switch event.Action {
            case "START":
                if cancels[event.URI] != nil {
                    panic("duplicate URI: " + event.URI)
                }
    
                ctx, cancel := context.WithCancel(ctx)
                cancels[event.URI] = cancel
                defer cancel() // cancel must always be called to free resources.
    
                go func(u string) {
                    // Awesome goroutine code
    
                    // Check ctx.Done or ctx.Err in strategic places and return if done.
                    select {
                    case <-ctx.Done():
                        return
                    default:
                    }
    
                    // More awesome goroutine code
    
                    if ctx.Err() != nil {
                        return
                    }
    
                    // Even more awesome goroutine code
    
                }(event.URI)
    
            case "STOP":
                if cancel, ok := cancels[event.URI]; ok {
                    cancel()
                    delete(cancels, event.URI)
                }
            }
        }
    }
    

    【讨论】:

    • 请记住,您的 goroutine 的 default: 案例需要定期让出控制权,否则它会愉快地跟风,从不检查它是否收到了 Context 的取消。
    • @JoeMcMahon,这就是我所说的“在战略位置检查 ctx”的意思。我希望更新现在很明显。
    • 确实如此,感谢您添加它。尝试调试该特定问题给我留下了伤痕!
    • 感谢大家提供这个很棒的解决方案。取消函数的映射很巧妙。
    猜你喜欢
    • 2011-10-12
    • 2020-02-14
    • 1970-01-01
    • 2016-11-05
    • 2017-07-19
    • 2018-04-24
    • 2018-02-19
    • 2018-08-14
    • 1970-01-01
    相关资源
    最近更新 更多