Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 如何将多个goroutine同步到所选goroutine的终止(即Thread.join())_Concurrency_Go - Fatal编程技术网

Concurrency 如何将多个goroutine同步到所选goroutine的终止(即Thread.join())

Concurrency 如何将多个goroutine同步到所选goroutine的终止(即Thread.join()),concurrency,go,Concurrency,Go,我在前面的一个问题中问过这个问题,但有些人觉得我最初的问题不够详细(“为什么你会想要一个定时条件等待?”),所以这里有一个更具体的问题 我有一个goroutine正在运行,称之为服务器。它已经启动,将执行一段时间,并完成它的工作。然后,它将在完成后退出 在执行过程中,会启动大量其他goroutine。如果您愿意,可以称它们为“客户端”线程。他们运行步骤A和步骤B。然后,他们必须等待“服务器”goroutine完成指定的时间,如果“服务器未完成”,则以状态退出,如果完成,则说运行步骤C (请不要告

我在前面的一个问题中问过这个问题,但有些人觉得我最初的问题不够详细(“为什么你会想要一个定时条件等待?”),所以这里有一个更具体的问题

我有一个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不支持定时条件等待。(但存在广播()

那么,“以围棋为中心”的方式是什么呢?我已经看过所有围棋博客和文档,这种模式或其等价物,尽管它很明显,但从未出现,也没有任何等价的“重构”基本问题是,IPC类型的通道位于一个例程和另一个例程之间。是的,有扇入/扇出,但请记住这些线程不断出现和消失。这应该很简单,而且至关重要的是,当mux通道的另一个“分支”(计时器)发出信号时,不会留下数千个“等待状态”goroutin等待服务器死亡

请注意,上面的一些“客户机”可能在服务器goroutine启动之前启动(这是通常创建通道的时候),有些可能在启动期间出现,有些可能在启动之后出现。。。在所有情况下,当且仅当服务器在进入Join()函数后的时间毫秒后运行并退出时,才应运行stepC


一般来说,当有多个消费者时,渠道设施似乎非常缺乏。“首先建立一个监听器映射到的通道的注册表”和“有一个非常漂亮的递归数据结构,它通过一个作为字段保存的通道发送自己”都是如此。not.ok作为友好、可靠、友好、明显的替代品:wait(forSomeTime)

我想你想要做的是在一个共享通道上选择,然后让服务器在完成后关闭它

假设我们创建一个全球“退出通道”,它在所有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")

}
更完整的示例:

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)

}
主程序包
进口(
“fmt”
“时间”
)
func服务员(ch chan结构{}){
fmt.Println(“做事”)
fmt.Println(“等待…”)
挑选{

案例这与我实际需要的非常接近-限制是我只能获得一点信息(是的,我知道这就是我所要求的-很难用普通的东西精确地解释我的实际用例)现在就说,而不是我们现在的“服务器完成了”“服务器已从一组离散的已知可能状态中获得新状态”。如果我可以执行以下操作之一(从通道接收时原子地获取互斥体(posix样式)|从n个通道接收全部或无(windows样式)|只接收某些类型的消息(旧学校的OO语言样式),我们将获得金牌。继续,马克回答了,因为这很有帮助,并且确实回答了我的问题。是的,我认为这很有效。这就像用一个频道来代替一个(一次性的)不过,条件变量广播,而不是作为频道。感觉有点骇人。但是,嘿,def会接受它。我根据这个答案开始实现类似的东西(我脑子里有close()语义错误!),现在我正尝试将它包装起来,以便发送到“广播频道”,而不是专门的函数(例如,Go like).TYVM。顺便说一句,为什么投反对票?问题有问题吗?请留下反馈。@BadZen我实际上对你的问题投了赞成票,但如果你想得到一些建设性的批评,你的问题有点长,你的问题有点难以理解,我甚至不确定我的解决方案是否是你想要的,你本可以做到的更抽象、更清楚一点。也许有人不喜欢这样。但这是一个好问题,我很高兴我能帮上这个关()的把戏,它在这种情况下救了我几次:)
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)

}
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")   
    }
}