Первое, на что нужно обратить внимание, - это три подпрограммы го, и все они независимы друг от друга.Единственное, что объединяет две подпрограммы go с подпрограммой подсчета, это канал, по которому обе подпрограммы go отправляют значения.
time.Sleep
не делает синхронные подпрограммы go.При использовании time.Sleep
вы фактически позволяете подпрограмме count
go ждать того времени, что позволяет другой подпрограмме go отправлять значение на канал, который доступен для подпрограммы count
go, чтобы иметь возможность ее получить.
Еще одна вещь, которую вы можете сделать, чтобы проверить это, это увеличить количество процессоров, что даст вам случайный результат.
func GOMAXPROCS(n int) int
GOMAXPROCS устанавливает максимальное количество процессоров, которое может бытьвыполняется одновременно и возвращает предыдущую настройку.Если n <1, это не меняет текущую настройку.Количество логических процессоров на локальном компьютере можно узнать с помощью NumCPU.Этот вызов прекратится, когда улучшится планировщик. </p>
Количество процессоров, доступных одновременно для выполнения подпрограмм, контролируется переменной среды оболочки GOMAXPROCS, значением по умолчанию которой является количество доступных процессорных ядер.Программы с возможностью параллельного выполнения должны, следовательно, достигать этого по умолчанию на машине с несколькими процессорами.Чтобы изменить число используемых параллельных процессоров, задайте переменную среды или используйте функцию с аналогичным именем пакета времени выполнения, чтобы настроить поддержку времени выполнения для использования другого количества потоков.Установка его в 1 исключает возможность истинного параллелизма, заставляя независимые программы выполнять операции по очереди.
Учитывая часть, где выходные данные процедуры go случайны, они всегда случайны.Но каналы, скорее всего, работают в очереди, которая является FIFO (первым пришел - первым вышел), так как это зависит от того, какое значение доступно на канале для приема b.Таким образом, какое бы значение не было доступно на канале, который нужно отправить, это позволяет подпрограмме count
go подождать и напечатать это значение.
Возьмем для примера, даже если я использую time.Sleep, результат является случайным:
package main
import (
"fmt"
"time"
)
func go1(msg_chan chan string) {
for i := 0; i < 10; i++ {
msg_chan <- fmt.Sprintf("%s%d", "go1:", i)
}
}
func go2(msg_chan chan string) {
for i := 0; i < 10; i++ {
msg_chan <- fmt.Sprintf("%s%d", "go2:", i)
}
}
func count(msg_chan chan string) {
for {
msg := <-msg_chan
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
func main() {
var c chan string
c = make(chan string)
go go1(c)
go go2(c)
go count(c)
time.Sleep(time.Second * 20)
fmt.Println("finished")
}
Это иногда приводит к состоянию гонки , поэтому мы используем синхронизацию либо с использованием каналов, либо wait.groups.
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func go1(msg_chan chan string) {
defer wg.Done()
for {
msg_chan <- "go1"
}
}
func go2(msg_chan chan string) {
defer wg.Done()
for {
msg_chan <- "go2"
}
}
func count(msg_chan chan string) {
defer wg.Done()
for {
msg := <-msg_chan
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
func main() {
var c chan string
c = make(chan string)
wg.Add(1)
go go1(c)
wg.Add(1)
go go2(c)
wg.Add(1)
go count(c)
wg.Wait()
fmt.Println("finished")
}
Теперь перейдем к той части, гдеВы используете бесконечный цикл для отправки значений на канал.Поэтому, если вы удалите time.Sleep
, ваш процесс будет зависать, поскольку цикл никогда не остановится для отправки значений на канал.