Golang 中的取消模式

Posted

技术标签:

【中文标题】Golang 中的取消模式【英文标题】:Cancellation pattern in Golang 【发布时间】:2019-06-02 00:35:59 【问题描述】:

这是来自50 Shades Of Go: Traps, Gotchas and Common mistakes的引用:

您还可以使用特殊的取消通道来中断 工人。

func First(query string, replicas ...Search) Result   
    c := make(chan Result)
    done := make(chan struct)
    defer close(done)
    searchReplica := func(i int)  
        select 
        case c <- replicas[i](query):
        case <- done:
        
    
    for i := range replicas 
        go searchReplica(i)
    

    return <-c

据了解,这意味着我们使用频道done提前中断worker而不等待完全执行(在我们的例子中执行replicas[i](query)。因此,我们可以从最快的worker接收结果(“First Wins Pattern”),然后取消所有其他工作人员的工作并节省资源。

另一方面,根据specification:

对于语句中的所有情况,receive 的通道操作数 操作以及 send 的通道和右侧表达式 语句在输入时按源顺序只计算一次 “选择”语句。

据我了解,这意味着我们不能interrupt the workers,因为无论如何,所有工作人员都会评估函数replicas[i]query,然后才会选择case &lt;- done并完成它们的执行。

您能指出我推理中的错误吗?

【问题讨论】:

【参考方案1】:

您的推理是正确的,网站上的措辞并不完全清楚。这个“构造”实现的是goroutines不会永远挂起,但是一旦搜索完成,goroutines就会正确结束。那里什么也没有发生。

一般来说,你不能从外部中断任何 goroutine,goroutine 本身必须支持某种终止(例如关闭通道,context.Context 等)。见cancel a blocking operation in Go。

所以是的,在您发布的示例中,所有搜索都将同时启动,最快的搜索结果将在到达时返回,其余的 goroutine 将继续运行,只要搜索完成。

其余的会发生什么?其余的将被丢弃(将选择case &lt;- done,因为无缓冲的通道不能容纳任何元素,并且不会有其他人从通道接收更多)。

您可以在此Go Playground example 中验证这一点。

【讨论】:

以上是关于Golang 中的取消模式的主要内容,如果未能解决你的问题,请参考以下文章

订单超时自动取消golang

sql golang查询时,无效的内存地址或nil指针取消引用。

golang Context for goroutines

golang - mysql 恐慌:运行时错误:无效的内存地址或 nil 指针取消引用

golang ctx取消没有按预期工作

Golang 演员模式