簡體   English   中英

我的 GoRoutines 完成運行后如何從通道讀取?

[英]How can I read from a channel after my GoRoutines have finished running?

我目前有兩個函數 pushNodes(node) 和 updateNodes(node)。 在 pushNodes function 中,我通過要在 updateNodes 中使用的通道推送值。 為了保存准確的通道值,我需要在啟動 updateNodes() 之前完成所有 pushNodes go 例程。 GoRoutines 完成執行后,如何仍然訪問通道值?

我不斷收到“致命錯誤:所有 goroutines 都睡着了 - 死鎖”。 請讓我知道如何從頻道中獲取這些值? 有沒有更好/替代的方法來做到這一點?

   //pushNodes is a function that will push the nodes values
   func pushNodes(node Node) {
      defer wg.Done()
      fmt.Printf("Pushing: %d \n", node.number)
      //Choose a random peer node
      var randomnode int = rand.Intn(totalnodes)
      for randomnode == node.number {
        rand.Seed(time.Now().UnixNano())
        randomnode = rand.Intn(totalnodes)
      }
      //If the current node is infected, send values through the channel
      if node.infected {
         sentchanneldata := ChannelData{infected: true, message: node.message}
         allnodes[randomnode].channel <- sentchanneldata
         fmt.Printf("Node %d sent a value of %t and %s to node %d!\n", node.number, sentchanneldata.infected, sentchanneldata.message, allnodes[randomnode].number)
    }


 //updateNodes is a function that will update the nodes values
  func updateNodes(node Node) {
    defer wg.Done()
    fmt.Printf("Updating: %d\n", node.number)
    //get value through node channel
    receivedchanneldata := <-node.channel
    fmt.Printf("Node %d received a value of %t and %s!\n", node.number, receivedchanneldata.infected, receivedchanneldata.message)
    // update value
    if receivedchanneldata.infected == true {
      node.infected = true
    }
    if receivedchanneldata.message != "" {
      node.message = receivedchanneldata.message
    }
    fmt.Printf("Update successful!\n")
  }

   //Part of main functions
    wg.Add(totalnodes)
    for node := range allnodes {
        go pushNodes(allnodes[node])
    }
    wg.Wait()
    fmt.Println("Infect function done!")

    wg.Add(totalnodes)
    for node := range allnodes {
        go updateNodes(allnodes[node])
    }
    wg.Wait()

GoRoutines 完成執行后,如何仍然訪問通道值?

通道的存在,包括任何已被推入其中的數據,都獨立於可能讀取或寫入它的 goroutines,前提是至少有一個 goroutine 仍然存在可以讀取和/或寫入它。 (一旦所有此類 goroutine 都消失了,通道最終將被 GC 處理。)

您的代碼示例無法使用( 如前所述),因此我們無法准確說明您哪里出錯了,但您會收到您在此處報告的那種fatal消息:

致命錯誤:所有 goroutines 都睡着了——死鎖!

如果您嘗試從最后一個可運行的 goroutine 中的通道讀取,這樣這個 goroutine 就會進入睡眠狀態以等待該通道的消息,這樣 Go 運行時的 rest 可以確定沒有當前處於睡眠狀態的 goroutine將永遠醒來並該頻道上傳遞消息。 例如,假設您總共有 7 個 goroutine 正在運行,其中一個運行到以下代碼行:

msg = <-ch

其中ch是一個開放通道,目前沒有可用數據。 這 7 個 goroutines 中的一個到達這條線並阻塞(“進入睡眠”),等待剩下的六個goroutines 之一做:

ch <- whatever

這將喚醒第 7 個 goroutine。 所以現在只有 6 個 goroutines 可以寫入ch或關閉ch 如果這六個剩余的 goroutines通過同一條線,一次一個或幾個或一次全部,並且它們都沒有在通道上發送或關閉它,那么那些剩余的 goroutines 也會阻塞。 當它們中的最后一個阻塞時,運行時將意識到程序被卡住了,並且 panic。

然而,如果剩下的六個 goroutines 中只有五個像這樣阻塞,那么第六個 goroutines 運行通過一行讀取:

close(ch)

close操作將關閉通道,導致所有六個“陷入沉睡”的 goroutine 接收到由零值“假”消息msg表示的“數據結束”。 您還可以使用接收的二值形式:

msg, ok = <-ch

如果通道關閉且msg包含真實消息,則oktrue ,但如果通道關閉且msg現在包含零值“ false ”消息,則為假。

因此,您可以:

  • 關閉頻道以表明您不打算發送任何其他內容,或者
  • 仔細匹配“從頻道接收”操作的數量與“在頻道上發送消息”操作的數量。

前者是通道的常態,沒有辦法提前知道應該在通道上發送多少消息。 即使您知道,它仍然可以使用。 進行關閉的典型構造是:

ch := make(chan T)  // for some type T
// do any other setup that is appropriate

var wg sync.WaitGroup
wg.add(N)  // for some number N
// spin off some number of goroutines N, each of which may send
// any number of messages on the channel
for i := 0; i < N; i++ {
    go doSomething(&wg, ch)
    // in doSomething, call wg.Done() when done sending on ch
}

go func() {
    wg.Wait()  // wait for all N goroutines to finish
    close(ch)  // then, close the channel
}()

// Start function(s) that receive from the channel, either
// inline or in more goroutines here; have them finish when
// they see that the channel is closed.

這種模式依賴於創建一個額外的第 N+1 個 goroutine 的能力——這是匿名的 function go func() {... }()序列——它一生的全部工作就是等待所有發送者我是發送完畢 每個發件人通過調用wg.Done()一次來完成此操作。 這樣,沒有發送者對關閉通道有任何特殊責任:他們都只是寫,然后在寫完后宣布“我寫完了”。 一個goroutine 有一個特殊的職責:它等待所有發送者宣布“我寫完了”,然后它關閉通道並退出,完成了它一生中的一項工作。

所有的接收者——無論是一個還是多個——現在很容易知道什么時候沒有人會再發送任何東西,因為他們在那個時候看到了一個關閉的通道。 因此,如果大部分工作都在發送端,您甚至可以在此處使用帶有簡單for... range ch循環的主 goroutine。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM