Несмотря на то, что это похоже на магию, оно имеет логическое объяснение. Go не гарантирует порядок выполнения goroutines. В данном фрагменте кода появилось три goroutines, но на самом деле их четыре: самая первая, которая создается при запуске.
Stdout print опущен
Эта рутина породила три функции сна и продолжила свой план. Это было так быстро, что он выполнил wg.Wait()
до того, как любая из порожденных горутин могла вызвать wg.Add(1)
. В результате wg.Wait()
не заблокировал выполнение и программа завершилась.
Печать на стандартный вывод до wg.Wait()
В этом случае выполнение программы было другим, программы могли выполнять вызов wg.Add(1)
, потому что основная программа была не быстрой, как в первом случае. Такое поведение не гарантируется, что можно увидеть на примере связанной игровой площадки.
Это не имеет ничего общего с выводом stdout
Следующий пример кода даст тот же ожидаемый результат:
time.Sleep(time.Second)
wg.Wait()
fmt.Println("all done")
fmt.Println()
оказал такое же воздействие, как time.Sleep()
.
Идиоматический способ
Правило простое: позвоните wg.Add(1)
перед тем, как порождать горутин.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
wg := new(sync.WaitGroup)
nap := func() {
time.Sleep(2 * time.Second)
fmt.Println("nap done")
wg.Done()
}
napCount := 3
wg.Add(napCount)
for i := 0; i < napCount; i++ {
go nap()
}
wg.Wait()
fmt.Println("all done")
}