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

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

如何將多個 goroutine 同步到選定 goroutine 的終止

如何將多個 goroutine 同步到選定 goroutine 的終止

Go
慕哥9229398 2021-10-04 09:36:51
我在上一個問題中問過這個問題,但有些人覺得我最初的問題不夠詳細(“為什么你想要一個定時條件等待??”)所以這里有一個更具體的問題。我有一個 goroutine 正在運行,稱之為服務器。它已經啟動,將執行一段時間,并做它的事情。然后,它會退出,因為它完成了。在它的執行過程中,一些其他的 goroutine 會啟動。如果您愿意,可以稱它們為“客戶端”線程。他們運行步驟 A 和步驟 B。然后,他們必須等待“服務器”goroutine 完成指定的時間,如果“服務器未完成,則退出狀態,如果完成則說運行步驟 C。”(請不要告訴我如何重組此工作流程。它是假設的和給定的。無法更改。)一個正常的、合理的方法是讓服務器線程用 selectAll 或 Broadcast 函數通知一個條件變量,并讓其他線程處于定時等待狀態監視條件變量。func (s *Server) Join(timeMillis int) error {  s.mux.Lock()  defer s.mux.Unlock()  while !s.isFinished {     err = s.cond.Wait(timeMillis)     if err != nil {        stepC()     }  }  return err}服務器將進入一個狀態,其中 isFinished 變為 true 并廣播關于互斥鎖的條件變量。除非這是不可能的,因為 Go 不支持定時條件等待。(但有一個 Broadcast())那么,什么是“以 Go 為中心”的方式來做到這一點?我已經了解了所有的 Go 博客和文檔,這種模式或其等價物,盡管很明顯,但從未出現,也沒有對基本問題進行任何等效的“重構”——即 IPC 風格的通道介于一個例程和一個例程之間其他例行公事。是的,有扇入/扇出,但請記住這些線程不斷出現和消失。這應該很簡單 - 并且至關重要的是/不要讓成千上萬的“等待狀態”goroutine 在復用通道的另一個“分支”(計時器)發出信號時等待服務器死亡/。請注意,上面的一些“客戶端”可能在服務器 goroutine 啟動之前啟動(這是通常創建通道的時間),一些可能出現在期間,一些可能出現在之后......在所有情況下,如果和,他們應該運行 stepC僅當服務器在進入 Join() 函數后 timeMillis 毫秒后運行并退出時...一般來說,當有多個消費者時,渠道設施似乎非常缺乏?!笆紫葮嫿ㄒ粋€將偵聽器映射到的通道注冊表”和“這是一個非常漂亮的遞歸數據結構,它通過它作為字段保存的通道發送自己”是這樣的: 等待(forSomeTime)
查看完整描述

1 回答

?
慕田峪9158850

TA貢獻1794條經驗 獲得超8個贊

我認為可以通過在單個共享通道上進行選擇,然后在完成后讓服務器關閉它來完成您想要的操作。


假設我們創建了一個全局“退出通道”,它在所有 goroutine 之間共享。它可以在創建“服務器”goroutine 之前創建。重要的部分是服務器 goroutine 從不向通道發送任何內容,而只是將其關閉。


現在客戶端 goroutines,只需執行以下操作:


select {

    case <- ch:

    fmt.Println("Channel closed, server is done!")

    case <-time.After(time.Second):

    fmt.Println("Timed out. do recovery stuff")


}

服務器 goroutine 只做:


close(ch)

更完整的例子:


package main


import(

    "fmt"

    "time"


)



func waiter(ch chan struct{}) {

    fmt.Println("Doing stuff")


    fmt.Println("Waiting...")


    select {

        case <- ch:

        fmt.Println("Channel closed")

        case <-time.After(time.Second):

        fmt.Println("Timed out. do recovery stuff")


    }

}



func main(){


    ch := make(chan struct{})


    go waiter(ch)

    go waiter(ch)

    time.Sleep(100*time.Millisecond)

    fmt.Println("Closing channel")

    close(ch)


    time.Sleep(time.Second)


}

這可以抽象為以下實用程序 API:


type TimedCondition struct {

    ch chan struct{}

}


func NewTimedCondition()*TimedCondition {

    return &TimedCondition {

        ch: make(chan struct{}),

    }

}


func (c *TimedCondition)Broadcast() {

    close(c.ch)

}


func (c *TimedCondition)Wait(t time.Duration) error {

    select {

        // channel closed, meaning broadcast was called

        case <- c.ch:

            return nil

        case <-time.After(t):

            return errors.New("Time out")   

    }

}


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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