Golang 中使用通道构建协程间的依赖关系(工作流)

假设有一组任务有前后依赖关系,我们可以使用Go的通道特性,将前一个任务的执行结果(或结束信号)送入下一个任务,已达到自动化依次执行工作流的每个任务的目的。

为了模拟这一工作流,我们假设有五个通道和四个协程,每个协程监听前一个通道的数据,并将接收到的数据送入下一个通道中。

当任务执行结束后,最好能够主动回收通道,已达到节省内存开销的目的。与执行工作流类似的是,应当能做到关闭首个通道后,按照依赖关系连锁关闭后续所有通道。

示例代码如下:https://go.dev/play/p/zcuEA7t_zSU

package main

import (
    "fmt"
    "time"
)

func main() {
    // 创建通道
    channels := make([]chan int, 5)
    for i := range channels {
        channels[i] = make(chan int)
    }

    // 设置协程
    for i := 0; i < len(channels)-1; i++ {
        i := i
        go func(in <-chan int, out chan<- int) {
            for {
                value, ok := <-in // 从前一个通道接收数据
                if !ok {
                    fmt.Printf("Channel[%d] closed. Exiting goroutine.\n", i)
                    close(out)
                    return
                }
                out <- value // 发送数据到下一个通道
            }
        }(channels[i], channels[i+1])
    }

    // 启动第一个协程,将数据发送到第一个通道
    go func(out chan<- int) {
        for i := 0; i < 10; i++ {
            out <- i // 发送数据到第一个通道
        }
        close(out) // 关闭第一个通道
    }(channels[0])

    // 从最后一个通道接收数据并打印
    for {
        select {
        case value, ok := <-channels[len(channels)-1]:
            if !ok {
                fmt.Println("Last channel closed. Exiting.")
                return
            }
            fmt.Println("Received:", value)
        case <-time.After(1 * time.Second):
            fmt.Println("Timeout. Exiting.")
            return
        }
    }
}

执行结果如下:

Received: 0
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Channel[0] closed. Exiting goroutine.
Channel[1] closed. Exiting goroutine.
Channel[2] closed. Exiting goroutine.
Received: 8
Received: 9
Channel[3] closed. Exiting goroutine.
Last channel closed. Exiting.

从执行结果中可以看出,最后一个协程的结果还未送出时,首个通道既已开始关闭。

你可能感兴趣的:(go协程channel工作流)