concurrency and timeout in Go

huangapple go评论97阅读模式
英文:

concurrency and timeout in Go

问题

这个Go程序有一些令人困惑的结果。当取消注释第11行时,它不按预期工作,即time.After 5秒的超时不会发生。但是当注释掉第11行并取消注释第12行时,超时会按预期工作。我对Go还不熟悉,但是我错过了什么吗?

以下是翻译好的代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	start := time.Now()

	sleep_durations := []int{8100, 1000, 2500, 500, 6000}
	// sleep_durations := []int{8100, 1000, 2500, 500}
	c := make(chan string)
	defer close(c) // main退出时关闭通道
	for index, duration := range sleep_durations {
		go sleepy(fmt.Sprintf("sleepy%d: ", index+1), duration, c)
	}
	fmt.Printf("开始 %d 个睡眠\n", len(sleep_durations))

	for range sleep_durations {
		select {
		case msg := <-c:
			fmt.Println("接收到:", msg)
		case <-time.After(time.Second * time.Duration(5)):
			fmt.Println("*** 超时 ***")
		}
	}

	elapsed := time.Since(start)
	fmt.Printf("... %d 个睡眠运行时间:%e\n", len(sleep_durations), elapsed.Seconds())
}

func sleepy(msg string, sleep_ms int, yawn chan string) {
	start := time.Now()
	sleep := time.Duration(sleep_ms) * time.Millisecond
	time.Sleep(sleep) // 一些需要睡眠的工作
	yawn <- fmt.Sprintf("%s 睡了 %s", msg, sleep)
	elapsed := time.Since(start)
	fmt.Printf("\t%s 完成时间:%s\n", msg, elapsed)
}

你可以在这里查看代码:https://play.golang.org/p/0ioTuKv230

当取消注释第11行时,超时不会按预期工作。这是因为在select语句中,time.After的超时通道会被阻塞,直到有一个case可以执行。当取消注释第11行时,sleep_durations中的所有goroutine都会在5秒之前完成,因此time.After的超时通道永远不会被选中,导致超时不会发生。

当注释掉第11行并取消注释第12行时,超时会按预期工作。这是因为取消注释第12行后,sleep_durations中的goroutine会在5秒之后才完成,这时time.After的超时通道会被选中,触发超时。

希望对你有帮助!如果还有其他问题,请随时问。

英文:

This Go program:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	start := time.Now()

	sleep_durations := []int{8100, 1000, 2500, 500, 6000}
	// sleep_durations := []int{8100, 1000, 2500, 500}
	c := make(chan string)
	defer close(c) // close channel when main exits
	for index, duration := range sleep_durations {
		go sleepy(fmt.Sprintf(&quot;sleepy%d: &quot;, index+1), duration, c)
	}
	fmt.Printf(&quot;starting %d sleepys\n&quot;, len(sleep_durations))

	for range sleep_durations {
		select {
		case msg := &lt;-c:
			fmt.Println(&quot;received: &quot;, msg)
		case &lt;-time.After(time.Second * time.Duration(5)):
			fmt.Println(&quot;*** TIMEOUT ***&quot;)
		}
	}

	elapsed := time.Since(start)
	fmt.Printf(&quot;... %d sleepys ran in: %e\n&quot;, len(sleep_durations), elapsed.Seconds())
}

func sleepy(msg string, sleep_ms int, yawn chan string) {
	start := time.Now()
	sleep := time.Duration(sleep_ms) * time.Millisecond
	time.Sleep(sleep) // some sleepy work
	yawn &lt;- fmt.Sprintf(&quot;%s slept for %s&quot;, msg, sleep)
	elapsed := time.Since(start)
	fmt.Printf(&quot;\t%s finished in: %s\n&quot;, msg, elapsed)
}

https://play.golang.org/p/0ioTuKv230

has confusing results. When line 11 is uncommented it does not work as expected, i.e. the time.After 5 seconds doesn't happen. But with line 11 commented and line 12 uncommented the timeout does work as expected. I'm new to Go, but what am I missing?

答案1

得分: 2

超时时间是每次选择调用的,如果每隔5秒(或更短)从通道中获取到内容,它将无限期地继续执行。

如果你希望超时时间适用于所有操作,可以这样做:

t := time.After(5 * time.Second)
for range sleep_durations {
    select {
    case msg := <-c:
        fmt.Println("received: ", msg)
    case <-t:
        fmt.Println("*** TIMEOUT ***")
    }
}

https://play.golang.org/p/r0_PyeE3bx

英文:

The timeout is per-select invocation, if it keeps getting something from the channel once every 5 seconds (or less) it will keep going indefinitely.

If you meant for the timeout to apply to all operations then do so like so:

	t := time.After(5 * time.Second)
	for range sleep_durations {
		select {
		case msg := &lt;-c:
			fmt.Println(&quot;received: &quot;, msg)
		case &lt;-t:
			fmt.Println(&quot;*** TIMEOUT ***&quot;)
		}
	}

https://play.golang.org/p/r0_PyeE3bx

答案2

得分: -1

我找到了你要翻译的内容:

我找到了我要找的东西

package main

import (
  "fmt"
  "sync"
  "time"
)

func main() {
  var wg sync.WaitGroup
  done := make(chan struct{})
  wq := make(chan interface{})
  worker_count := 2

  for i := 0; i < worker_count; i++ {
    wg.Add(1)
    go doit(i, wq, done, &wg)
  }

  fmt.Printf("doing work\n")
  for i := 0; i < worker_count; i++ {
    time.Sleep(time.Millisecond * time.Duration(100))
    wq <- fmt.Sprintf("worker: %d", i)
  }

  fmt.Printf("closing 'done' channel\n")
  close(done)
  fmt.Printf("block/wait until all workers are done\n")
  wg.Wait()
  fmt.Println("all done!")
}

func doit(worker_id int, wq <-chan interface{}, done <-chan struct{}, wg *sync.WaitGroup) {
  fmt.Printf("[%v] is working\n", worker_id)
  defer wg.Done()
  max_time := time.Second * time.Duration(5)
  for {
    select {
    case m := <-wq:
      fmt.Printf("[%v] m => %v\n", worker_id, m)
    case <-done:
      fmt.Printf("[%v] is done\n", worker_id)
      return
    case <-time.After(max_time):
      fmt.Printf("timeout > %s seconds!\n", max_time)
    }
  }
}

请确认以上翻译是否准确无误。

英文:

I found what I was looking for:

package main
import (
&quot;fmt&quot;
&quot;sync&quot;
&quot;time&quot;
)
func main() {
var wg sync.WaitGroup
done := make(chan struct{})
wq := make(chan interface{})
worker_count := 2
for i := 0; i &lt; worker_count; i++ {
wg.Add(1)
go doit(i, wq, done, &amp;wg)
}
fmt.Printf(&quot;doing work\n&quot;)
for i := 0; i &lt; worker_count; i++ {
time.Sleep(time.Millisecond * time.Duration(100))
wq &lt;- fmt.Sprintf(&quot;worker: %d&quot;, i)
}
fmt.Printf(&quot;closing &#39;done&#39; channel\n&quot;)
close(done)
fmt.Printf(&quot;block/wait until all workers are done\n&quot;)
wg.Wait()
fmt.Println(&quot;all done!&quot;)
}
func doit(worker_id int, wq &lt;-chan interface{}, done &lt;-chan struct{}, wg *sync.WaitGroup) {
fmt.Printf(&quot;[%v] is working\n&quot;, worker_id)
defer wg.Done()
max_time := time.Second * time.Duration(5)
for {
select {
case m := &lt;-wq:
fmt.Printf(&quot;[%v] m =&gt; %v\n&quot;, worker_id, m)
case &lt;-done:
fmt.Printf(&quot;[%v] is done\n&quot;, worker_id)
return
case &lt;-time.After(max_time):
fmt.Printf(&quot;timeout &gt; %s seconds!\n&quot;, max_time)
}
}
}

huangapple
  • 本文由 发表于 2015年7月28日 02:25:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/31660524.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定