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

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

關閉由通道鏈接的 goroutine 鏈的優雅方法是什么?

關閉由通道鏈接的 goroutine 鏈的優雅方法是什么?

Go
慕的地8271018 2021-12-07 10:44:48
我是圍棋學習者。為了更好地理解通道和 goroutine 的關心和饋送,我試圖構建一個 Eratosthenes 篩,作為一組通過通道連接到管道中的 goroutine。這是我到目前為止所擁有的:// esieve implements a Sieve of Eratosthenes// as a series of channels connected together// by goroutinespackage mainimport "fmt"func sieve(mine int, inch chan int) {    start := true                        // First-number switch    ouch := make(chan int)               // Output channel for this instance    fmt.Printf("%v\n", mine)             // Print this instance's prime    for next := <-inch; next > 0; next = <-inch {  // Read input channel        fmt.Printf("%v <- %v\n",mine,next)         // (Trace)        if (next % mine) > 0 {                     // Divisible by my prime?            if start {                   // No; is it the first number through?                 go sieve(next, ouch)     // First number - create instance for it                start = false            // First time done            } else {                     // Not first time                ouch <- next             // Pass it to the next instance            }        }    }}func main() {    lim := 30                     // Let's do up to 30    fmt.Printf("%v\n", 2)         // Treat 2 as a special case    ouch := make(chan int)        // Create the first segment of the pipe    go sieve(3, ouch)             // Create the instance for '3'    for prime := 3; prime < lim; prime += 2 { // Generate 3, 5, ...        fmt.Printf("Send %v\n", prime)        // Trace        ouch <- prime                         // Send it down the pipe    }}就目前而言,它運行良好。但是,當我完成主循環時,main在sieve實例管道中的所有數字傳播到最后之前退出。使主例程等待一組 goroutines(它只“知道”第一個)完成的最簡單、最優雅或普遍接受的方法是什么?
查看完整描述

2 回答

?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

并且在一切都完成后出現了一些涉及死鎖的錯誤啟動之后,這是我的解決方案正常工作:


// esieve implements a Sieve of Eratosthenes

// as a series of channels connected together

// by goroutines

package main


import "fmt"


func sieve(mine int,                  // This instance's own prime

           inch chan int,             // Input channel from lower primes

           done chan int,             // Channel for signalling shutdown

           count int) {               // Number of primes - counter

    start := true                     // First-number switch

    ouch := make(chan int)            // Output channel, this instance

    fmt.Printf("%v ", mine)           // Print this instance's prime

    for next := <-inch; next > 0; next = <-inch { // Read input channel

        if (next % mine) > 0 {        // Divisible by my prime?

            if start {                // No; first time through?

                go sieve(next, ouch, done, count+1) // First number,

                                                    // create instance for it

                start = false         // First time done

            } else {                  // Not first time

                ouch <- next          // Pass to next instance

            }

        }

    }

    if start {                        // Just starting?

        close(done)                   // Yes - we're last in pipe - signal done

        print("\n",count," primes\n") // Number of primes/goroutines

    } else {

        close(ouch)                   // No - send the signal down the pipe

    }

}


func main() {

    lim := 100                        // Let's do up to 100

    done := make(chan int)            // Create the done return channel

    ouch := make(chan int)            // Create the first segment of the pipe

    go sieve(2, ouch, done, 1)        // Create the first instance for '2'

    for prime := 3; prime < lim; prime += 1 { // Generate odd numbers

        ouch <- prime                         // Send numbers down the pipe

    }

    close(ouch)                       // Send the done signal down the pipe

    <- done                           // and wait for it to come back

}

與許多其他語言相比,Go 對于這種編程的優雅和簡單給我留下了深刻的印象。當然,疣是我自己要求的。


如果在這里合適,我歡迎批評性評論。


查看完整回答
反對 回復 2021-12-07
?
狐的傳說

TA貢獻1804條經驗 獲得超3個贊

至于您的標題問題,當您不再需要它們時殺死工作程序 goroutine: 您可以使用 Done 成語。從封閉通道讀取產生零值。


創建一個新頻道done。當從這個通道讀取成功時,goroutines 知道他們應該退出。當您擁有所需的所有值時,關閉主通道。


檢查您是否可以從 channel 讀取done,并通過返回退出,或者在可用時從 next 讀取。這部分替換了nextfor 循環中的賦值:


select {

case <-done:

return

case next = <- inch:

}

在通道上測距也有效,因為關閉該通道退出循環。


至于反過來,你的身體問題,等待一組goroutines完成:


使用sync.WaitGroup.


var wg sync.WaitGroup

wg.Add(goroutineCount)

當每個 goroutine 完成時:


wg.Done()

或者使用延遲:


defer wg.Done()

等待所有這些都報告為完成:


wg.Wait()

在您的示例中,只需wg.Add(1)在啟動新 goroutine 時調用,然后再調用wg.Done()和返回即可。只要您只達到零一次,就會wg.Wait()按預期工作,所以wg.Add(1)在wg.Done.


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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