英文:
Writing Sleep function based on time.After
问题
我的问题与https://stackoverflow.com/questions/31942163/how-to-write-my-own-sleep-function-using-just-time-after不同。它有一个不同的代码变体,由于不同的原因而无法工作,我需要解释为什么。
我正在尝试解决这里的作业问题:https://www.golang-book.com/books/intro/10(使用time.After
编写自己的Sleep函数)。
根据该章节中讨论的示例,这是我目前的尝试:
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)
}
我的思路是无限的for
循环将不断执行select
语句的default
部分,直到time.After
函数返回的通道发出信号。当前代码的问题是,后者没有发生,而default
语句被无限调用。
我做错了什么?
英文:
EDIT: My question is different from https://stackoverflow.com/questions/31942163/how-to-write-my-own-sleep-function-using-just-time-after It has a different variant of the code that's not working for a separate reason and I needed explanation as to why.
I'm trying to solve the homework problem here: https://www.golang-book.com/books/intro/10 (Write your own Sleep function using time.After
).
Here's my attempt so far based on the examples discussed in that chapter:
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
My thought process is that the infinite for
will keep executing the select
statement's default
until the time.After
function's returned channel talks. Problem with the current code being, the latter does not happen, while the default
statement is called infinitely.
What am I doing wrong?
答案1
得分: 6
在你的for
循环的每次迭代中,将执行select
语句,其中涉及评估通道操作数。
在每次迭代中,将调用time.After()
并创建一个新的通道!
如果持续时间大于0
,则该通道尚未准备好接收数据,因此将执行默认情况。该通道将不会再次被测试/检查,下一次迭代将创建一个新的通道,该通道仍然无法接收数据,因此将再次选择default
情况-一如既往。
解决方案非常简单,如此答案所示:
func Sleep(sec int) {
<-time.After(time.Second * time.Duration(sec))
}
修复你的变体:
如果你想让你的变体工作,你只需要创建一个通道(使用time.After()
),存储返回的通道值,并始终检查该通道。如果通道"触发"(从中接收到一个值),你必须从函数中返回,因为不会再接收到更多的值,所以你的循环将一直无限执行!
func myOwnSleep(duration int) {
ch := time.After(time.Second * time.Duration(duration))
for {
select {
case <-ch:
fmt.Println("slept!")
return // 必须返回,否则无限循环!
default:
fmt.Println("Waiting")
}
}
}
请注意,尽管在从通道接收到值之前,此函数不会"休息",而是无休止地执行代码-占用一个CPU核心。如果只有1个CPU核心可用(runtime.GOMAXPROCS()
),其他的goroutine(包括将在通道上发送值的goroutine)可能会被阻塞并永远不会执行。一个休眠(例如time.Sleep(time.Millisecond)
)可以释放CPU核心,使其不再执行无休止的工作(并允许其他的goroutine运行)。
英文:
In each iteration of your for
loop the select
statement is executed which involves evaluating the channel operands.
In each iteration time.After()
will be called and a new channel will be created!
And if duration is more than 0
, this channel is not ready to receive from, so the default case will be executed. This channel will not be tested/checked again, the next iteration creates a new channel which will again not be ready to receive from, so the default
case is chosen again - as always.
The solution is really simple though as can be seen in this answer:
func Sleep(sec int) {
<-time.After(time.Second* time.Duration(sec))
}
Fixing your variant:
If you want to make your variant work, you have to create one channel only (using time.After()
), store the returned channel value, and always check this channel. And if the channel "kicks in" (a value is received from it), you must return from your function because more values will not be received from it and so your loop will remain endless!
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")
}
}
}
Note that though until a value is received from the channel, this function will not "rest" and just execute code relentlessly - loading one CPU core. This might even give you trouble if only 1 CPU core is available (runtime.GOMAXPROCS()
), other goroutines (including the one that will (or would) send the value on the channel) might get blocked and never executed. A sleep (e.g. time.Sleep(time.Millisecond)
) could release the CPU core from doing endless work (and allow other goroutines to run).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论