实施工作人员职能流水线

时间:2018-10-14 12:39:39

标签: go goroutine

我正在实现由通道连接的多个工作程序功能的管道。它们全部都以(in, out chan interface{})作为输入(每个函数将上一个的out作为in接收)

我不能保证out将在每个函数的结尾处关闭,因此我想知道如何检查以前的函数是否已完成工作。我开始是这样的:

func ExecutePipeline(jobs ...job) {
    out := make(chan interface{}, 10)
    for _, val := range jobs {
        in := out
        out := make(chan interface{})
        go val(in, out)
    }
}

我正在考虑使用WaitGroup以某种方式使用函数结尾的goroutine作为完成工作并关闭其输出通道的指标。
我该怎么做?

1 个答案:

答案 0 :(得分:0)

如果您的目的是沿管道传播信号以在先前的管道阶段完成时进行通信,并且不会再产生任何值,则可以在每个管道阶段返回后通过关闭通道来同步执行此操作。下面的代码通过包装每个管道工作程序的调用来做到这一点:

func startWork(val job, in, out chan interface{}) {
    val(in, out)
    // out will be closed after val returns
    close(out)
}

// Later, in ExecutePipeline, start your worker by calling startWork
func ExecutePipeline(jobs ...job) {
    // ...
    for _, val := range jobs {
        // ...
        go startWork(val, in, out)
    }
}

避免多渠道关闭

  

我不能保证out将在每个函数结束时关闭

相反,如果有任何工人 可以关闭渠道,这是有问题的;如果您尝试关闭一个已经关闭的频道,那么startWork中随后关闭该频道的调用就会惊慌。

在这种简单的实现中,工作人员必须将通道关闭委托给监督管道的代码,以免导致程序崩溃。


处理带内信令

由于信令是在带内(与数据在同一通道中)传递的,因此在实施管道工人时可能需要小心以确保它们之间的区别

  • 从公开渠道读取值,并且
  • 从封闭的通道读取零值
range循环中的通道上

for切换会在通道关闭时自动中断循环。如果您实现自己的逻辑以读取通道,则由于通道关闭,您将需要确定何时成功以零值成功读取。这可以使用multi-valued assignment form of the receive operator来实现,当从通道读取的值为零(因为通道已关闭且为空)时,它将返回一个布尔值。

func someWorker(in, out chan interface{}) {
    for {
        val, open := <-in
        if !open {
            // Read of val was the zero value of "in", indicating the channel
            // is closed.
            break // or, if appropriate, return
        }
    }
}