【发布时间】:2019-11-19 19:27:20
【问题描述】:
我正在尝试为重复性任务实现并发。我想在不同的 Goroutine 上实现一个 http 请求(由longRunningTask 函数描绘)。我提供了一个计时器,用于停止 Goroutine 并向主 Goroutine 发送超时信号,如果重负载任务继续预定义的超时。我目前遇到的问题是我出现间歇性行为。
代码已简化为如下所示。
package main
import (
"fmt"
"time"
)
func main() {
var iteration int = 5
timeOutChan := make(chan struct{})
resultChan := make(chan string)
for i := 0; i < iteration; i++ {
go longRunningTaks(timeOutChan, resultChan)
}
for i := 0; i < iteration; i++ {
select {
case data := <-resultChan:
fmt.Println(data)
case <-timeOutChan:
fmt.Println("timed out")
}
}
}
func longRunningTaks(tc chan struct{}, rc chan string) {
timer := time.NewTimer(time.Nanosecond * 1)
defer timer.Stop()
// Heavy load task
time.Sleep(time.Second * 1)
select {
case <-timer.C:
tc <- struct{}{}
case rc <- "success":
return
}
}
我相信每次尝试都应该打印出来
timeout
timeout
timeout
timeout
timeout
相反,我得到了间歇性
success
timeout
timeout
timeout
timeout
【问题讨论】:
-
"If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection." rc 上的发送很可能会继续进行,因为 main 中有匹配的接收。您的程序根本就不是确定性的。
-
@Peter 我不太明白,当睡眠时间长于超时时间时,rc 如何进行?另外,您所说的不仅仅是确定性是什么意思?
-
@Adam 您的“超时”不会超时。您总是等待睡眠完成,然后检查前一段时间是否发生了“超时”;您在查看是否可以发送结果的同一步骤中进行检查。两者都是可能的,选择哪一个是完全任意的。这不是您在 Go 中执行超时的方式。
标签: go concurrency goroutine channels