猿问

使用sync.WaitGroup.wait时如何实现超时?

我遇到过一种情况,我想跟踪某个 goroutine 以在特定点上进行同步,例如在获取所有 url 时。然后,我们可以将它们全部放置并按特定顺序显示。


我认为这是障碍进来的。它是在go与sync.WaitGroup. 但是,在实际情况下,我们无法确保所有的 fetch 操作都会在短时间内成功。所以,我想wait在获取操作时引入超时。


我是新手Golang,所以有人可以给我一些建议吗?


我正在寻找的是这样的:


   wg := &sync.WaigGroup{}

   select {

   case <-wg.Wait():

   // All done!

   case <-time.After(500 * time.Millisecond):

   // Hit timeout.

   }

我知道Wait不支持Channel。


慕娘9325324
浏览 351回答 3
3回答

慕桂英4014372

如果你想要的只是你的简洁选择,你可以通过生成一个调用方法并在完成后关闭/发送通道的例程来轻松地将阻塞功能转换为通道。done := make(chan struct{})go func() {&nbsp; &nbsp;wg.Wait()&nbsp; &nbsp;close(done)}()select {case <-done:// All done!case <-time.After(500 * time.Millisecond):// Hit timeout.}

慕尼黑的夜晚无繁华

将您的结果发送到一个缓冲通道,足以获取所有结果,而不会阻塞,并在主线程的 for-select 循环中读取它们:func work(msg string, d time.Duration, ret chan<- string) {&nbsp; &nbsp; time.Sleep(d) // Work emulation.&nbsp; &nbsp; select {&nbsp; &nbsp; case ret <- msg:&nbsp; &nbsp; default:&nbsp; &nbsp; }}// ...const N = 2ch := make(chan string, N)go work("printed", 100*time.Millisecond, ch)go work("not printed", 1000*time.Millisecond, ch)timeout := time.After(500 * time.Millisecond)loop:for received := 0; received < N; received++ {&nbsp; &nbsp; select {&nbsp; &nbsp; case msg := <-ch:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(msg)&nbsp; &nbsp; case <-timeout:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("timeout!")&nbsp; &nbsp; &nbsp; &nbsp; break loop&nbsp; &nbsp; }}游乐场:http : //play.golang.org/p/PxeEEJo2dz。

慕标5832272

另一种方法是在内部对其进行监控,您的问题是有限的,但我假设您正在通过循环启动 goroutines,即使您不是,您也可以重构它来为您工作,但您可以这样做这两个示例之一,第一个将超时每个请求单独超时,第二个将超时整批请求,如果时间过长则继续var wg sync.WaitGroupwg.Add(1)go func() {&nbsp; &nbsp; success := make(chan struct{}, 1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; // send your request and wait for a response&nbsp; &nbsp; &nbsp; &nbsp; // pretend response was received&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(5 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; success <- struct{}{}&nbsp; &nbsp; &nbsp; &nbsp; // goroutine will close gracefully after return&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Returned Gracefully")&nbsp; &nbsp; }()&nbsp; &nbsp; select {&nbsp; &nbsp; case <-success:&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; case <-time.After(1 * time.Second):&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()&nbsp; &nbsp; // everything should be garbage collected and no longer take up space}()wg.Wait()// do whatever with what you got&nbsp; &nbsp;&nbsp;fmt.Println("Done")time.Sleep(10 * time.Second)fmt.Println("Checking to make sure nothing throws errors after limbo goroutine is done")或者,如果您只是想要一个通用的简单方法来超时所有请求,您可以执行以下操作var wg sync.WaitGroupwaiter := make(chan int)wg.Add(1)go func() {&nbsp; &nbsp; success := make(chan struct{}, 1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; // send your request and wait for a response&nbsp; &nbsp; &nbsp; &nbsp; // pretend response was received&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(5 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; success <- struct{}{}&nbsp; &nbsp; &nbsp; &nbsp; // goroutine will close gracefully after return&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Returned Gracefully")&nbsp; &nbsp; }()&nbsp; &nbsp; select {&nbsp; &nbsp; case <-success:&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; case <-time.After(1 * time.Second):&nbsp; &nbsp; &nbsp; &nbsp; // control the timeouts for each request individually to make sure that wg.Done gets called and will let the goroutine holding the .Wait close&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()&nbsp; &nbsp; // everything should be garbage collected and no longer take up space}()completed := falsego func(completed *bool) {&nbsp; &nbsp; // Unblock with either wait&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; if !*completed {&nbsp; &nbsp; &nbsp; &nbsp; waiter <- 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; *completed = true&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; fmt.Println("Returned Two")}(&completed)go func(completed *bool) {&nbsp; &nbsp; // wait however long&nbsp; &nbsp; time.Sleep(time.Second * 5)&nbsp; &nbsp; if !*completed {&nbsp; &nbsp; &nbsp; &nbsp; waiter <- 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; *completed = true&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; fmt.Println("Returned One")}(&completed)&nbsp;// block until it either times out or .Wait stops blocking&nbsp;&nbsp;<-waiter// do whatever with what you got&nbsp; &nbsp;&nbsp;fmt.Println("Done")time.Sleep(10 * time.Second)fmt.Println("Checking to make sure nothing throws errors after limbo goroutine is done")这样你的 WaitGroup 将保持同步,你不会有任何 goroutines 处于不确定状态http://play.golang.org/p/g0J_qJ1BUT在这里试试你可以改变周围的变量以查看它的工作方式不同编辑:我在移动设备上如果有人可以修复格式,那将是非常感谢。
随时随地看视频慕课网APP

相关分类

Go
我要回答