【问题标题】:golang timer blocking in goroutinesgoroutine中的golang计时器阻塞
【发布时间】:2014-07-19 19:27:15
【问题描述】:

以下代码来自go by example - timers

package main

import (
    "time"
    "fmt"
)

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    timer1 := time.NewTimer(time.Second * 1)

    <-timer1.C
    fmt.Println("Timer 1 expired")

    timer2 := time.NewTimer(300) //change the duration to be more shorter
    go func() {
        <-timer2.C
        fmt.Printf("Timer 2 expired")
    }()

    stop2 := timer2.Stop()
    if stop2 {
        fmt.Printf("Timer 2 stopped")
    }
}

如果我运行上面的代码,输出将是这样的(结果一):

Timer 1 expired
Timer 2 stopped

但如果我将匿名函数的主体更改为:

fmt.Printf("Timer 2 expired")
<-timer2.C

输出还是和以前一样。我很困惑,为什么第二个输出不像(结果二):

Timer 1 expired
Timer 2 expired
Timer 2 stopped

根据我的理解 会阻塞 goroutine 的剩余部分,直到计时器通道得到一个值,所以如果我把 fmt.Printf("Timer 2 expired") 之后的输出会像结果一,但如果我把 fmt.Printf("Timer 2 expired") 放在 ,我认为打印动作不会被阻塞。

希望有人能帮帮我,谢谢大家。

【问题讨论】:

    标签: timer go blocking goroutine


    【解决方案1】:

    问题很可能是打印语句和程序结束之间没有保证"happens before" 关系。当主 Goroutine 退出时,整个程序退出。

    Goroutines 有一个启动时间,运行时有几个条件来判断它何时切换到另一个正在运行的 goroutine。可能发生的情况是匿名函数中没有任何代码被执行,因为主 goroutine 缺少任何阻塞操作(甚至是昂贵的函数调用),很快就退出了

    更改GOMAXPROCS,就像这个程序试图做的那样,有时可以“修复”这个问题,因为多个线程有一个机会潜入一些代码,因为它们不必依赖在运行时的显式上下文切换上,但没有保证“发生在之前”的关系,或者至少没有一些声明故意使主 goroutine 挂起一段时间(例如空的select{}for{} 等)你不能依赖实际运行的主 goroutine 之外的任何代码。

    完全有可能在完全不同的机器上(或者甚至是负载较少的同一台机器,或超频或......),您会得到您期望的行为。不幸的是,正如您所了解的,您不能指望它,请确保同步您的 goroutine。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-18
      • 2014-12-24
      • 2019-11-04
      • 1970-01-01
      • 2016-07-06
      • 1970-01-01
      • 2020-10-12
      • 2020-04-03
      相关资源
      最近更新 更多