编辑:我的问题与How to write my own Sleep function using just time.After?有所不同它有一个不同的代码变体,由于单独的原因无效,我需要解释原因。
我正在尝试解决这里的作业问题:https://www.golang-book.com/books/intro/10(使用time.After
编写自己的睡眠功能)。
这是我到目前为止基于该章讨论的例子的尝试:
package main
import (
"fmt"
"time"
)
func myOwnSleep(duration int) {
for {
select {
case <-time.After(time.Second * time.Duration(duration)):
fmt.Println("slept!")
default:
fmt.Println("Waiting")
}
}
}
func main() {
go myOwnSleep(3)
var input string
fmt.Scanln(&input)
}
http://play.golang.org/p/fb3i9KY3DD
我的思维过程是无限for
将继续执行select
语句的default
,直到time.After
函数返回的频道会话。当前代码存在问题,后者不会发生,而default
语句被无限调用。
我做错了什么?
答案 0 :(得分:5)
在for
循环的每次迭代中,执行select
语句,包括评估通道操作数。
在每次迭代中,将调用time.After()
并创建一个新频道!
如果持续时间超过0
,则此通道尚未准备好接收,因此将执行默认情况。此通道不会再次进行测试/检查,下一次迭代会创建一个新的通道,该通道将再次无法接收,因此会再次选择default
大小写 - 一如既往。
虽然在this answer中可以看到解决方案非常简单:
func Sleep(sec int) {
<-time.After(time.Second* time.Duration(sec))
}
修复您的变体:
如果要使变体工作,则必须仅创建一个通道(使用time.After()
),存储返回的通道值,并始终检查此通道。如果频道&#34;踢出&#34; (从中收到一个值),你必须从你的函数返回,因为不会从它接收到更多的值,所以你的循环将保持无穷无尽!
func myOwnSleep(duration int) {
ch := time.After(time.Second * time.Duration(duration))
for {
select {
case <-ch:
fmt.Println("slept!")
return // MUST RETURN, else endless loop!
default:
fmt.Println("Waiting")
}
}
}
请注意,虽然直到从频道收到一个值,但此功能不会休息&#34;并且只是无情地执行代码 - 加载一个CPU核心。如果只有1个CPU核心可用(runtime.GOMAXPROCS()
),这甚至可能会给您带来麻烦,其他goroutine(包括将(或将会)在通道上发送值的goroutine可能会被阻止并且从未执行过。睡眠(例如time.Sleep(time.Millisecond)
)可以释放CPU核心进行无休止的工作(并允许其他goroutine运行)。