Это может прояснить некоторые вещи, чтобы немного переписать тело цикла for в goroutine:
x := <-c
// block until a value has been read, then continue
fmt.Println(x)
fmt.Printf("%v from main\n",i)
И, аналогично, тело цикла select в fibonacci()
эффективно:
c <- x
// block until a value has been written, then continue
fmt.Printf("(%v, %v)\n", x ,y)
x, y = y, x+y
fmt.Printf("(%v, %v)\n", x ,y)
В обоих случаях у вас есть гарантия, что второй оператор печати будет напечатан после первого.
Когда вы запустите программу, скажите, что программа запускается немедленно.Он доходит до этого чтения, но в канале нет значения, поэтому он блокируется.Тогда основная программа вызывает fibonacci()
.Он попадает в оператор выбора.Для канала c
имеется считыватель, поэтому он отправляет туда номер x
.
Как только это произойдет и , программа и основная программа свободны.Оператор select запустил одну из своих ветвей и отправил свое значение;чтение завершено.Обе программы свободны для запуска и могут делать это в любом порядке (при условии, что каждая выполняет свои собственные инструкции по порядку).В конечном итоге вы достигнете точки, в которой либо блокировка программы на чтение, либо блокировка fibonacci()
на выбор, и как только оба догонят друг друга, оба будут свободны для выполнения снова.
порядок, который вы предлагаете, потребовал бы, чтобы читатель «проснулся» раньше, чем это сделал писатель, но ничто в Go не требует этого, и действительно, в многоядерной системе оба могут работать одновременно.