为什么主goroutine总是第二个被调用

为什么主goroutine总是第二个被调用,go,concurrency,goroutine,Go,Concurrency,Goroutine,结果: package main import ( "sync" "time" ) func main() { var wg sync.WaitGroup wg.Add(1) go func() { //A wg.Wait() println("wait exit") }() go func() { time.Sleep(time.Second) wg.Done() }() wg.Wait() p

结果:

package main
import (
  "sync"
  "time"
  )
func main() {
  var wg sync.WaitGroup

  wg.Add(1)

  go func() {         //A
    wg.Wait()
    println("wait exit")
  }()

  go func() {
    time.Sleep(time.Second)
    wg.Done()
  }()

  wg.Wait()
  println("main exit")
}
为什么主goroutine不先执行println(“主出口”),主线程死了,然后放弃goroutine? 它像结果显示的那样持续打印

语言规范中没有规定“等待退出”应该在“主退出”之前或之后执行


如果你运行程序的次数足够多,有时“主出口”会先运行。但也可能不是。结果未定义,取决于运行时状态和实现。因为这样的结果甚至可能在Go版本之间发生变化。

我已经尝试过很多次,如果这是偶然决定的,我想它可能至少会出现一次。@JunAn尝试使用-race运行程序。当使用-race编译goroutines时,运行时会在一定程度上随机改变goroutines的运行顺序。大多数情况下,使用-race我会得到不同的输出。@JunAn:顺序没有定义,这意味着当前运行时实现可能仍然以一致的方式影响顺序。如果您使用的是游乐场,那么每次都检索相同的缓存结果。在不创建顺序的情况下,不要依赖顺序。除了上面的答案和注释外,在2个打印goroutines中添加
runtime.LockOSThread()
,并多次运行,我运行了一次,只打印了“主出口”(程序在打印其他文本之前终止)。作为记录,在单核系统上,goroutine调度在很大程度上是确定性的。有可能输入一个函数来重新调度该goroutine(以防止连续旋转的例程导致线程饱和),但除此之外,调度器对何时可以发生goroutine交换(阻塞通道操作、网络调用、睡眠等)有一致的规则。这种行为没有很好的文档记录,也没有在规范中定义,因此可以在不通知的情况下更改实现,并且不会破坏向后兼容性保证。
wait exit
main exit