为了账号安全,请及时绑定邮箱和手机立即绑定

基于时间编写睡眠函数。之后

基于时间编写睡眠函数。之后

Go
慕沐林林 2021-11-08 19:37:19
编辑:我的问题与How to write my own Sleep function using just time.After 不同?它有一个不同的代码变体,由于单独的原因而无法正常工作,我需要解释原因。我正在尝试在这里解决作业问题:https : //www.golang-book.com/books/intro/10(使用编写您自己的睡眠功能time.After)。到目前为止,这是我基于该章节中讨论的示例所做的尝试:package mainimport (        "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我的想法是,infinitefor将继续执行select语句,default直到time.After函数返回的通道说话。当前代码的问题是,后者不会发生,而default语句被无限调用。我究竟做错了什么?
查看完整描述

1 回答

?
POPMUISE

TA贡献1765条经验 获得超5个赞

在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 // MUST RETURN, else endless loop!

        default:

            fmt.Println("Waiting")

        }

    }

}

请注意,尽管在从通道接收到值之前,此函数不会“休息”,只会无情地执行代码 - 加载一个 CPU 内核。如果只有 1 个 CPU 内核可用runtime.GOMAXPROCS(),这甚至可能会给您带来麻烦(),其他 goroutine(包括将(或将)发送到通道上的值的 goroutine)可能会被阻塞并且永远不会执行。睡眠(例如time.Sleep(time.Millisecond))可以释放 CPU 内核,使其免于无休止的工作(并允许其他 goroutine 运行)。


查看完整回答
反对 回复 2021-11-08
  • 1 回答
  • 0 关注
  • 183 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信