英文:
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 (
"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) // close channel when main exits
for index, duration := range sleep_durations {
go sleepy(fmt.Sprintf("sleepy%d: ", index+1), duration, c)
}
fmt.Printf("starting %d sleepys\n", len(sleep_durations))
for range sleep_durations {
select {
case msg := <-c:
fmt.Println("received: ", msg)
case <-time.After(time.Second * time.Duration(5)):
fmt.Println("*** TIMEOUT ***")
}
}
elapsed := time.Since(start)
fmt.Printf("... %d sleepys ran in: %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) // some sleepy work
yawn <- fmt.Sprintf("%s slept for %s", msg, sleep)
elapsed := time.Since(start)
fmt.Printf("\t%s finished in: %s\n", 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 := <-c:
fmt.Println("received: ", msg)
case <-t:
fmt.Println("*** TIMEOUT ***")
}
}
答案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 (
"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)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论