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

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

Go - 如何知道輸出通道何時完成

Go - 如何知道輸出通道何時完成

Go
慕的地6264312 2021-09-10 14:53:05
我嘗試遵循 Rob Pike 在“并發不是并行”的演講中的例子,并做了這樣的事情:我正在啟動許多 go 例程作為從輸入通道讀取的工作人員,執行一些處理,然后通過輸出通道發送結果.然后我開始另一個 go 例程,它從某個源讀取數據并通過他們的輸入通道將其發送給工作人員。最后,我想遍歷輸出通道中的所有結果并對其進行處理。問題是,由于工作在工作人員之間分配,我不知道所有工作人員何時完成,因此我可以停止向輸出通道詢問更多結果,并且我的程序可以正常結束。了解工作人員何時完成將結果發送到輸出通道的最佳做法是什么?
查看完整描述

3 回答

?
阿晨1998

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

var Z = "Z"


func Loop() {

    sc := make(chan *string)

    ss := make([]string, 0)

    done := make(chan struct{}, 1)

    go func() {

        //1 QUERY

        slice1 := []string{"a", "b", "c"}

        //2 WG INIT

        var wg1 sync.WaitGroup

        wg1.Add(len(slice1))

        //3 LOOP->

        loopSlice1(slice1, sc, &wg1)

        //7 WG WAIT<-

        wg1.Wait()

        sc <- &Z

        done <- struct{}{}

    }()


    go func() {

        var cc *string

        for {

            cc = <-sc

            log.Infof("<-sc %s", *cc)

            if *cc == Z {

                break

            }

            ss = append(ss, *cc)

        }

    }()

    <-done

    log.Infof("FUN: %#v", ss)

}


func loopSlice1(slice1 []string, sc chan *string, wg1 *sync.WaitGroup) {

    for i, x := range slice1 {

        //4 GO

        go func(n int, v string) {

            //5 WG DONE

            defer wg1.Done()

            //6 DOING

            //[1 QUERY

            slice2 := []string{"X", "Y", "Z"}

            //[2 WG INIT

            var wg2 sync.WaitGroup

            wg2.Add(len(slice2))

            //[3 LOOP ->

            loopSlice2(n, v, slice2, sc, &wg2)

            //[7 WG WAIT <-

            wg2.Wait()

        }(i, x)

    }

}


func loopSlice2(n1 int, v1 string, slice2 []string, sc chan *string, wg2 *sync.WaitGroup) {

    for j, y := range slice2 {

        //[4 GO

        go func(n2 int, v2 string) {

            //[5 WG DONE

            defer wg2.Done()

            //[6 DOING

            r := fmt.Sprintf("%v%v %v,%v", n1, n2, v1, v2)

            sc <- &r

        }(j, y)

    }

}


查看完整回答
反對 回復 2021-09-10
?
不負相思意

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

請我首先澄清您的術語:對渠道末端的誤解可能會導致以后出現問題。您詢問“輸出通道”和“輸入通道”。哪有這回事; 只有渠道。


每個通道都有兩端:輸出(寫入)端和輸入(讀?。┒?。我會假設這就是你的意思。


現在回答你的問題。


以最簡單的情況為例:您只有一個發送方 goroutine 寫入通道,并且只有一個工作 goroutine 從另一端讀取,并且通道的緩沖為零。發送方 goroutine 將在寫入每個項目時阻塞,直到該項目被消耗。通常,這在第一次發生時很快。一旦第一個項目傳遞給工作人員,工作人員就會很忙,發件人必須等待才能傳遞第二項內容。因此,乒乓效應如下:作者或讀者會忙,但不會兩者都忙。在 Rob Pike 所描述的意義上,goroutine 將是并發的,但實際上并不總是并行執行。


如果您有許多從通道讀取的工作程序 goroutine(并且其輸入端由所有人共享),則發送方最初可以將一個項目分發給每個工作程序,但隨后必須等待它們工作(類似于上面描述的乒乓球案例)。最后,當所有項目都由發送方發送后,它的工作就完成了。然而,讀者可能還沒有完成他們的工作。有時我們關心發件人是否提前完成,有時我們不關心。知道何時發生這種情況最容易通過 WaitGroup 完成(參見Not_a_Golfer的回答和我對相關問題的回答)。


還有一個稍微復雜一點的替代方法:您可以使用返回通道來完成信號傳輸,而不是使用WaitGroup. 這并不難做到,但WaitGroup在這種情況下是首選,更簡單。


相反,如果通道包含緩沖區,則發送方發送最后一項的時間點會更快發生。在通道每個 worker 有一個緩沖區空間的極限情況下;這將允許發件人非??焖俚赝瓿?,然后,可能繼續處理其他事情。(任何比這更多的緩沖都是浪費)。


發送者的這種解耦允許完全異步的行為模式,深受使用其他技術堆棧(Node-JS 和 JVM 的人)的人的喜愛。與它們不同的是,Go不需要您這樣做,但您可以選擇。


早在 90 年代初期,作為批量同步并行 (BSP) 策略工作的副作用,Leslie Valiant 證明有時非常簡單的同步策略可能很便宜。關鍵因素是需要足夠的并行松弛(也稱為過度并行)來保持處理器內核忙碌。這意味著必須有足夠多的其他工作要做,以便任何特定的 goroutine 被阻塞一段時間都無關緊要。


奇怪的是,這可能意味著使用較少數量的 goroutine 可能比使用較大數量的 goroutine 需要更多的小心。


了解過度并行的影響是有用的:如果整個網絡具有過度并行,通常沒有必要付出額外的努力來使所有內容異步,因為無論哪種方式,CPU 內核都會很忙。


因此,雖然知道如何等待發件人完成很有用,但更大的應用程序可能不需要您以同樣的方式關注。


作為最后一個腳注,WaitGroup是BSP 中使用的意義上的障礙。通過結合障礙和渠道,您可以同時使用 BSP 和 CSP。


查看完整回答
反對 回復 2021-09-10
?
aluckdog

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

我個人喜歡為此使用 a sync.WaitGroup。等待組是一個同步計數器,它具有三種方法 - Wait()、Done()和Add()。您要做的是增加等待組的計數器,將其傳遞給工作人員,并讓Done()他們在完成后調用。然后,您只需阻塞另一端的等待組并在它們全部完成后關閉輸出通道,從而導致輸出處理器退出。


基本上:


// create the wait group

wg := sync.WaitGroup{}


// this is the output channel

outchan := make(chan whatever)


// start the workers

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

   wg.Add(1) //we increment by one the waitgroup's count


   //the worker pushes data onto the output channel and calls wg.Done() when done

   go work(&wg, outchan)

}


// this is our "waiter" - it blocks until all workers are done and closes the channel

go func() {

  wg.Wait()

  close(outchan)

}()


//this loop will exit automatically when outchan is closed

for item := range outchan {

   workWithIt(item)

}


// TADA!


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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