退出工作池中的通道

时间:2019-05-10 14:03:39

标签: go goroutine

我最终要完成的工作是根据工作量动态地放大或缩小我的工人。

当Task通过w.Channel到达时,下面的代码成功解析了数据

func (s *Storage) StartWorker(w *app.Worker) {

    go func() {

        for {

            w.Pool <- w.Channel // register current worker to the worker pool

            select {

            case task := <-w.Channel: // received a work request, do some work

                time.Sleep(task.Delay)

                fmt.Println(w.WorkerID, "processing task:", task.TaskName)

                w.Results <- s.ProcessTask(w, &task)

            case <-w.Quit:
                fmt.Println("Closing channel for", w.WorkerID)
                return
            }

        }
    }()

}

这里的阻塞点是下面的线。

w.Pool <- w.Channel

从这个意义上讲,如果我尝试使用以下方法停止程序中任何部分的工作人员:

w.Quit <- true

case <-w.Quit:被阻止,直到 w.Channel 上有另一个传入的Task时,它才接收(我猜这里的select语句对于每个案例选择都是随机的)。

那么我该如何独立停止频道(工作人员)?

1 个答案:

答案 0 :(得分:0)

请参见下面的示例代码,它声明了一个扇出功能,负责放大/缩小工作人员的人数。

通过使用超时来检测新工作人员已结束或需要产生新工作人员来进行工作。

存在一个内部循环,以确保在继续进行之前处理每个项目,并在需要时阻止源。

package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "os"
)

func main() {
    input := make(chan string)
    fanout(input)
}

func fanout() {
    workers := 0
    distribute := make(chan string)
    workerEnd := make(chan bool)
    for i := range input {
        done := false 
        for done {
            select {
            case distribute<-i:
                done = true
            case <-workerEnd:
                workers--
            default:
                if workers <10 {
                    workers++
                    go func(){
                        work(distribute)
                        workerEnd<-true
                    }()
                }
            }   
        }
    }
}

func work(input chan string) {
    for  {
        select {
        case i := <-input:
            <-time.After(time.Millisecond)
        case <-time.After(time.Second):
            return
        }

    }
}