Порядок выполнения при чтении из буферизованного канала в goroutine - PullRequest
0 голосов
/ 14 марта 2019

Я играл с параллельными и буферизованными каналами и столкнулся со следующей проблемой, которая оставила меня в замешательстве: https://play.golang.org/p/wir7wP2u-yf

  1. Почему именно «разгрузка» канала (размером 3) внутри функции echo происходит с включенными 4?

  2. Почему пропускная способность канала c остается равной 0 после того, как 5 отправлено на канал?

  3. Почему 10 не отражается?

package main

import "fmt"

func echo(c chan int) {
    for num := range c {
        //fmt.Printf("length of channel c: %v\n",len(c))
        fmt.Println(num)
    }
    fmt.Println("Done iterating")
}

func main() {
    fmt.Println("main() started")
    c := make(chan int, 3)

    go echo(c)

    c <- 1
    fmt.Printf("After 1, capacity %v\n",len(c))
    c <- 2
    fmt.Printf("After 2, capacity %v\n",len(c))
    c <- 3
    fmt.Printf("After 3, capacity %v\n",len(c))
    c <- 4 // blocks here
    fmt.Printf("After 4, capacity %v\n",len(c))
    c <- 5
    fmt.Printf("After 5, capacity %v\n",len(c))
    c <- 6
    fmt.Printf("After 6, capacity %v\n",len(c))
    c <- 7
    fmt.Printf("After 7, capacity %v\n",len(c))
    c <- 8
    fmt.Printf("After 8, capacity %v\n",len(c))
    c <- 9
    fmt.Printf("After 9, capacity %v\n",len(c))
    c <- 10
    fmt.Printf("After 10\n")
    fmt.Println("main() stopped")
}

1 Ответ

0 голосов
/ 14 марта 2019

Это полностью зависит от планирования ОС.Результаты приведенного выше кода не всегда будут одинаковыми.

main() started
After 1, capacity 1
After 2, capacity 2
After 3, capacity 3
1
2
3
4
After 4, capacity 0
After 5, capacity 0
After 6, capacity 1
After 7, capacity 2
After 8, capacity 3
5
6
7
8
9
After 9, capacity 0
After 10
main() stopped

Этот результат может быть таким же, как вы видели на детской площадке.Но это непредсказуемо, потому что мы не можем определить, как ОС планирует расписание выполнения подпрограмм.

Если я запускаю этот код на своей локальной машине, он будет отличаться при каждом его выполнении.См. Ниже:

Первый запуск

main() started
After 1, capacity 1
After 2, capacity 1
After 3, capacity 2
1
2
3
4
After 4, capacity 3
After 5, capacity 0
5
After 6, capacity 0
After 7, capacity 1
After 8, capacity 2
After 9, capacity 3
6
7
8
9
10
After 10
main() stopped

Второй запуск

main() started
After 1, capacity 1
After 2, capacity 2
1
2
3
After 3, capacity 2
After 4, capacity 0
4
5
After 5, capacity 1
After 6, capacity 0
After 7, capacity 1
After 8, capacity 2
6
7
8
9
After 9, capacity 3
After 10
main() stopped
10

Так что ответы на ваши вопросы будут

  1. Получение канала (для 4) только что было выполнено до fmt.Printf в основной функции.Это может отличаться при каждом исполнении.Попробуйте это на своем локальном компьютере.

  2. Похоже на 1. Он только что прочитал range перед len(c).

  3. Основная программавыход перед чтением 10 из канала.В этом случае вам следует подождать, пока все элементы в канале будут прочитаны с использованием некоторых методов, таких как время сна, группа ожидания пакета синхронизации или другой канал.

Вы можете увидеть, как этоПрограмма работает, вставляя time.Sleep(time.Second) между строк, которые вы хотите проверить.

Например, если вы спите в течение 1 секунды перед fmt.Println("main() stopped"), вы всегда можете увидеть эхо 10, потому что основная программа будетждать секунду.(1 секунда достаточно большая для чтения элемента из канала)

package main

import "fmt"
import "time"

func echo(c chan int) {
    for num := range c {
        fmt.Println(num)
    }
    fmt.Println("Done iterating")
}

func main() {
    fmt.Println("main() started")
    c := make(chan int, 3)

    go echo(c)

    c <- 1
    fmt.Printf("After 1, capacity %v\n",len(c))
    c <- 2
    fmt.Printf("After 2, capacity %v\n",len(c))
    c <- 3
    fmt.Printf("After 3, capacity %v\n",len(c))
    c <- 4 // blocks here
    fmt.Printf("After 4, capacity %v\n",len(c))
    c <- 5
    fmt.Printf("After 5, capacity %v\n",len(c))
    c <- 6
    fmt.Printf("After 6, capacity %v\n",len(c))
    c <- 7
    fmt.Printf("After 7, capacity %v\n",len(c))
    c <- 8
    fmt.Printf("After 8, capacity %v\n",len(c))
    c <- 9
    fmt.Printf("After 9, capacity %v\n",len(c))
    c <- 10
    fmt.Printf("After 10\n")
    time.Sleep(time.Second)
    fmt.Println("main() stopped")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...