какая программа выполняется при использовании sleep in go? - PullRequest
0 голосов
/ 27 сентября 2018

Я недавно в Голанге.У меня есть вопрос о Goroutine, когда использовать функцию time.sleep.здесь код.

package main

import (
    "fmt"
    "time"
)

func go1(msg_chan chan string) {
    for {
        msg_chan <- "go1"
    }
}
func go2(msg_chan chan string) {
    for {
        msg_chan <- "go2"
    }
}
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)
    var input string
    fmt.Scanln(&input)
}

и вывод

go1
go2
go1
go2
go1
go2

Я думаю, что когда функция count выполняет функцию сна, go1 и go2 будут выполняться в случайной последовательности.поэтому выход может быть как

go1
go1
go2
go2
go2
go1

, когда я удаляю код сна в функции подсчета.результат, как я и предполагал, случайный.я застрял в этом вопросе.спасибо.

1 Ответ

0 голосов
/ 27 сентября 2018

Первое, на что нужно обратить внимание, - это три подпрограммы го, и все они независимы друг от друга.Единственное, что объединяет две подпрограммы 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, ваш процесс будет зависать, поскольку цикл никогда не остановится для отправки значений на канал.

...