亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

關閉緩沖通道時是否應該將其排空

關閉緩沖通道時是否應該將其排空

Go
狐的傳說 2021-12-20 15:20:50
給定 Go 中(部分)填充的緩沖通道ch := make(chan *MassiveStruct, n)for i := 0; i < n; i++ {    ch <- NewMassiveStruct()}是否建議在關閉通道時(由作者)也排空通道,以防讀者何時從中讀?。ɡ?,數量有限并且他們目前正忙)?那是close(ch)for range ch {}如果通道上還有其他并發閱讀器,這樣的循環是否保證結束?上下文:具有固定數量工作器的隊列服務,當服務關閉時,它應該停止處理任何排隊的東西(但不一定在之后被 GC 處理)。所以我要向工作人員表明服務正在終止。我可以立即排空剩余的“隊列”,讓 GC 釋放分配的資源,我可以讀取和忽略工作程序中的值,我可以離開通道,因為讀取器正在運行,并將通道設置為 nil 在寫入器中GC 清理一切。我不確定哪種方式最干凈。
查看完整描述

3 回答

?
FFIVE

TA貢獻1797條經驗 獲得超6個贊

這取決于您的程序,但一般來說我傾向于說不(您不需要在關閉頻道之前清除頻道):如果您關閉頻道時頻道中有項目,任何仍在從頻道閱讀的讀者都會接收項目,直到通道為空。


下面是一個例子:


package main


import (

    "sync"

    "time"

)


func main() {


    var ch = make(chan int, 5)

    var wg sync.WaitGroup

    wg.Add(1)


    for range make([]struct{}, 2) {

        go func() {

            for i := range ch {

                wg.Wait()

                println(i)

            }

        }()

    }


    for i := 0; i < 5; i++ {

        ch <- i

    }

    close(ch)


    wg.Done()

    time.Sleep(1 * time.Second)

}

在這里,程序將輸出所有項目,盡管通道在任何讀者甚至可以從通道讀取之前嚴格關閉。


查看完整回答
反對 回復 2021-12-20
?
嚕嚕噠

TA貢獻1784條經驗 獲得超7個贊

有更好的方法來實現您想要實現的目標。您當前的方法只會導致丟棄一些記錄,并隨機處理其他記錄(因為排水循環正在與所有消費者競爭)。這并沒有真正解決目標。


你想要的是取消。這是Go 并發模式中的一個示例:管道和取消


func sq(done <-chan struct{}, in <-chan int) <-chan int {

    out := make(chan int)

    go func() {

        defer close(out)

        for n := range in {

            select {

            case out <- n * n:

            case <-done:

                return

            }

        }

    }()

    return out

}

您將一個done通道傳遞給所有 goroutine,并在您希望它們都停止處理時關閉它。如果你經常這樣做,你可能會發現這個golang.org/x/net/context包很有用,它正式化了這個模式,并添加了一些額外的功能(比如超時)。



查看完整回答
反對 回復 2021-12-20
?
動漫人物

TA貢獻1815條經驗 獲得超10個贊

我覺得所提供的答案實際上并沒有澄清,除了不需要排水也不需要關閉的提示。因此,針對所描述的上下文的以下解決方案對我來說看起來很干凈,它終止了工作人員并刪除了對他們或相關頻道的所有引用,因此,讓 GC 清理頻道及其內容:


type worker struct {

    submitted chan Task

    stop      chan bool

    p         *Processor

}


// executed in a goroutine

func (w *worker) run() {

    for {

        select {

        case task := <-w.submitted:

            if err := task.Execute(w.p); err != nil {

                logger.Error(err.Error())

            }

        case <-w.stop:

            logger.Warn("Worker stopped")

            return

        }

    }

}


func (p *Processor) Stop() {

    if atomic.CompareAndSwapInt32(&p.status, running, stopped) {

        for _, w := range p.workers {

            w.stop <- true

        }

        // GC all workers as soon as goroutines stop

        p.workers = nil

        // GC all published data when workers terminate

        p.submitted = nil

        // no need to do the following above:

        // close(p.submitted)

        // for range p.submitted {}

    }

}


查看完整回答
反對 回復 2021-12-20
  • 3 回答
  • 0 關注
  • 171 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號