基于 time.After 编写 Sleep 函数
Writing Sleep function based on 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
语句被无限调用。
我做错了什么?
在 for
循环的每次迭代中,都会执行 select
语句,其中涉及评估通道操作数。
在每次迭代中将调用 time.After()
并创建一个新频道!
并且如果持续时间超过0
,则此通道未准备好接收,因此将执行默认情况。此频道将不会再次 tested/checked,下一次迭代将创建一个新频道,该频道将再次无法接收,因此再次选择 default
案例 - 一如既往。
解决方案非常简单,但可以在 :
中看到
func Sleep(sec int) {
<-time.After(time.Second* time.Duration(sec))
}
修复您的变体:
如果你想让你的变体工作,你必须只创建一个通道(使用 time.After()
),存储 returned 通道值,并始终检查这个通道。如果通道"kicks in"(从中接收到一个值),你必须从你的函数中return,因为不会从它接收更多的值,所以你的循环将保持无限!
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")
}
}
}
请注意,尽管在从通道接收到值之前,此函数不会 "rest" 并且只会不懈地执行代码 - 加载一个 CPU 核心。如果只有 1 CPU 个核心可用(runtime.GOMAXPROCS()
),这甚至可能会给您带来麻烦,其他 goroutines(包括将(或将)在通道上发送值的 goroutines)可能会被阻塞并且永远不会执行.睡眠(例如 time.Sleep(time.Millisecond)
)可以释放 CPU 核心,使其不再做无休止的工作(并允许其他 goroutines 运行)。
编辑:我的问题与
我正在尝试解决这里的作业问题: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
语句被无限调用。
我做错了什么?
在 for
循环的每次迭代中,都会执行 select
语句,其中涉及评估通道操作数。
在每次迭代中将调用 time.After()
并创建一个新频道!
并且如果持续时间超过0
,则此通道未准备好接收,因此将执行默认情况。此频道将不会再次 tested/checked,下一次迭代将创建一个新频道,该频道将再次无法接收,因此再次选择 default
案例 - 一如既往。
解决方案非常简单,但可以在
func Sleep(sec int) {
<-time.After(time.Second* time.Duration(sec))
}
修复您的变体:
如果你想让你的变体工作,你必须只创建一个通道(使用 time.After()
),存储 returned 通道值,并始终检查这个通道。如果通道"kicks in"(从中接收到一个值),你必须从你的函数中return,因为不会从它接收更多的值,所以你的循环将保持无限!
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")
}
}
}
请注意,尽管在从通道接收到值之前,此函数不会 "rest" 并且只会不懈地执行代码 - 加载一个 CPU 核心。如果只有 1 CPU 个核心可用(runtime.GOMAXPROCS()
),这甚至可能会给您带来麻烦,其他 goroutines(包括将(或将)在通道上发送值的 goroutines)可能会被阻塞并且永远不会执行.睡眠(例如 time.Sleep(time.Millisecond)
)可以释放 CPU 核心,使其不再做无休止的工作(并允许其他 goroutines 运行)。