Я думаю, что вы наблюдаете, что Go имеет свой собственный планировщик, и в то же время существует различие между «параллелизмом» и «параллелизмом».По словам Роба Пайка: Параллелизм - это не параллелизм
Горутины намного легче, чем потоки ОС, и ими управляют в «пользовательской среде» (в процессе Go), а не в операционнойсистема.В некоторых программах запущено много тысяч (даже десятков тысяч) подпрограмм, хотя, безусловно, будет выделено гораздо меньше потоков операционной системы.(Это одно из главных преимуществ Go в асинхронных программах с большим количеством подпрограмм)
Поскольку ваша программа очень проста и канал буферизован, она не блокируется при записи в канал:
c <- x
фибоначчи не прерывается до завершения короткого цикла.
Даже fmt.Println("here")
не детерминированно вводит вытеснение - я сам кое-что узнал, написав этот ответ.Он буферизован, как аналогичные printf и scanf из C .(см. исходный код https://github.com/golang/go/blob/master/src/fmt/print.go)
. Для интереса, если вы хотите искусственно контролировать количество потоков ОС, вы можете установить переменную среды GOMAXPROCS в командной строке:
~$ GOMAXPROCS=1 go run main.go
Однако, с вашей простой программой, вероятно, не будет заметной разницы , потому что среда выполнения Go по-прежнему отлично способна планировать множество процедур для одного потока ОС.
ДляНапример, вот небольшая вариация вашей программы: уменьшив буфер канала (5), но повторяя его 10 раз, мы вводим точку, в которой процедура fibonacci go может (но не обязательно) быть прерванным, где он может заблокировать хотя бы один раз при записи в канал:
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
fmt.Println("here")
}
close(c)
}
func main() {
c := make(chan int, 5)
go fibonacci(cap(c)*2, c)
for i := range c {
fmt.Println(i)
}
}
~$ GOMAXPROCS=1 go run main.go
here
here
here
here
here
here
0
1
1
2
3
5
8
here
here
here
here
13
21
34
Длинное объяснение здесь , краткое объяснение состоит в том, что существует множество причин, по которым процедура goможет временно заблокировать, и для планировщика go это идеальные возможности для планирования выполнения другой подпрограммы go.