我正在尝试为重复性任务实现并发。我想在其他Goroutine(由longRunningTask
函数实现)上实现http请求。我提供了一种计时器,用于在重载任务进行预定义的超时时停止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
答案 0 :(得分:-1)
医生提到:
NewTimer创建一个新的Timer,它将在其上发送当前时间 至少持续时间d 之后的频道。
“至少意味着”计时器肯定会占用指定的时间,但是这也暗含意味着可能花费比指定的时间更多的时间。计时器启动其自己的go例程,并在到期时写入通道。 由于调度程序或垃圾回收,写入其他通道的过程可能会延迟。考虑到上述可能性,模拟工作量非常短。
更新:
正如彼得在评论中提到的那样,将“成功”写入rc通道的动作同样可能完成,因为它可以由主例程从另一端读取。选择必须在以下两者之间进行选择:1)将“成功”写入rc通道,以及2)过期计时器。两者都有可能。 开始时No1的可能性更大,因为主例程尚未从另一端读取它。一旦发生这种情况。其他剩余的例程将必须对该通道进行竞争(写入“成功”)(因为它正在使用缓冲区大小0进行阻塞),因此在其余时间中,选择过期定时器的可能性更大无法说主例程从resultChan通道(rc的另一端)读取的速度。