Нужна помощь в понимании логики параллелизма горутина, выбора и канала - PullRequest
0 голосов
/ 30 ноября 2018

Я пытаюсь понять логику параллелизма goroutine, select и channel.Пример кода приведен ниже.Базовый код взят из тура.Я добавил немного Printf, чтобы лучше понять.

package main
import "fmt"
func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            fmt.Printf("(%v, %v)\n", x ,y)
            x, y = y, x+y
            fmt.Printf("(%v, %v)\n", x ,y)
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}
func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 4; i++ {
            fmt.Println(<-c)
            fmt.Printf("%v from main\n",i)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

Вывод

0
0 from main
(0, 1)
(1, 1)
(1, 1)
(1, 2)
1
1 from main
1
2 from main
(1, 2)
(2, 3)
(2, 3)
(3, 5)
2
3 from main
quit

Существует параллелизм за работой рутин и каналов.Мой вопрос, почему вывод не

0
0 from main
(0, 1)
(1, 1)
1
1 from main
(1, 1)
(1, 2)
1
2 from main
(1, 2)
(2, 3)
2
3 from main
(2, 3)
(3, 5)
quit

1 Ответ

0 голосов
/ 30 ноября 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...