【问题标题】:how to safely close a chan chan T in Go?如何安全地关闭 Go 中的 chan chan T?
【发布时间】:2018-05-11 19:05:51
【问题描述】:

我正在实现一个简单的工作池算法,其中 1 个 Sender(调度程序)将作业发送到 M(Worker)去例程。为此,它使用通道通道为第一个空闲工作人员分配一个可用作业:

// builds the pool
func NewWorkerPool(maxWorkers int) WorkerPool {
    pool := make(chan chan Job, maxWorkers)
    workers := make([]Worker, 0)
    return WorkerPool{
        WorkerPool: pool,
        Workers: workers,
        maxWorkers: maxWorkers,
        waitGroup: sync.WaitGroup{}}
}

// Starts the WorkerPool
func (p *WorkerPool) Run(queue chan Job) {
    w := p.waitGroup

    // starting n number of workers
    for i := 0; i < p.maxWorkers; i++ {
        worker := NewWorker(p.WorkerPool)
        p.Workers = append(p.Workers, worker)
        w.Add(1)
        worker.Start(&w)
    }

    go p.dispatch(queue)
}

// dispatches a job to be handled by an idle Worker of the pool
func (p *WorkerPool) dispatch(jobQueue chan Job) {
    for {
        select {
        case job := <-jobQueue:
            // a model request has been received
            go func(job Job) {
                // try to obtain a worker model channel that is available.
                // this will block until a worker is idle
                jobChannel := <-p.WorkerPool

                // dispatch the model to the worker model channel
                jobChannel <- job
            }(job)
        }
    }
}


// checks if a Worker Pool is open or closed - If we can recieve on the channel then it is NOT closed
func (p *WorkerPool) IsOpen() bool {
    _, ok := <-p.WorkerPool
    return ok
}

worker 的 Start 和 Stop 方法

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w Worker) Start(wg *sync.WaitGroup) {
    go func() {
        defer wg.Done()
        for {
            // register the current worker into the worker queue.
            w.WorkerPool <- w.JobChannel

            select {
            case job := <-w.JobChannel:
                // we have received a work request.
                result := job.Run()
                job.ReturnChannel <- result

                // once result is returned close the job output channel
                close(job.ReturnChannel)

            case <-w.quit:
                // we have received a signal to stop
                return
            }
        }
    }()
}

// Stop signals the worker to stop listening for work requests.
func (w Worker) Stop() {
    go func() {
        w.quit <- true
    }()
}

现在我正在尝试使用以下方法关闭池,我使用了一个 sync.WaitGroup 来等待所有工作人员关闭:

// stops the Pool
func (p *WorkerPool) Stop() bool {
    // stops all workers
    for _, worker := range p.Workers {
        worker.Stop()
    }
    p.waitGroup.Wait() //Wait for the goroutines to shutdown

    close(p.WorkerPool)

    more := p.IsOpen()

    fmt.Printf(" more? %t", more)

    return ok
}

// 打印更多?是的

即使我等待工人退出并稍后调用 close(p.WorkerPool) 我仍然打开通道,在这种情况下缺少什么,如何相应地关闭通道?

【问题讨论】:

    标签: multithreading go synchronization shutdown


    【解决方案1】:

    关闭通道表示不再向其发送值。这对于向通道的接收者传达完成信息很有用。

    通道中的数据仍然存在,您可能需要关闭通道,然后像下面这样删除其中的所有通道

    // Stop stops the Pool and free all the channels
    func (p *WorkerPool) Stop() bool {
        // stops all workers
        for _, worker := range p.Workers {
            worker.Stop()
        }
        p.waitGroup.Wait() //Wait for the goroutines to shutdown
        close(p.WorkerPool)
        for channel := range p.WorkerPool {
            fmt.Println("Freeing channel") //remove all the channels
        }
        more := p.IsOpen()
        fmt.Printf(" more? %t", more)
    
        return ok
    }
    

    顺便说一句,不能使用_, ok &lt;- 来检查通道是否关闭。我会为函数建议一个不同的名称

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 2022-01-22
      • 2015-08-31
      • 2015-02-22
      • 2018-12-16
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多