Простой пример о Go Channel с тупиком и почему - PullRequest
0 голосов
/ 12 января 2019

Мой код выглядит следующим образом:

package main

import (
    "fmt"
)

func main() {
    c1 := make(chan int)
    fmt.Println("push c1: ")
    c1 <- 10
    g1 := <- c1
    fmt.Println("get g1: ", g1)
}

когда я отлаживаю с delve, он печатает этот результат:

push c1:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
        D:/Go/projects/hello-world/src/ch9/code9_6/code1.go:10 +0xde
Process 6276 has exited with status 2

Я не знаю, почему, это всего лишь один простой пример канала, я создаю один канал, отправляю значение и получаю значение из него, только это, кто-то может сказать мне, почему и как это исправить, большое спасибо ,

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Канал может быть буферизованным или небуферизованным (это означает, что в него можно отправить единственное значение переменной), и когда вы пытаетесь читать из небуферизованного канала, вы блокируете программу, в которой вы пытаетесь выполнить эту операцию. Чтобы разблокировать его, вы должны записать в канал в другой программе и наоборот, то есть, когда вы пишете в канал, вы блокируете программу, в которой вы выполняете эту операцию, но она будет разблокирована, когда вы попытаетесь прочитать из канал в другом рутине. Вы должны изучить эту функцию для разработки гибких (с параллелизмом) программ. Каналы используются для отправки данных между различными подпрограммами, которые должны работать независимо или параллельно. Вы можете создать конвейер из двух, трех или более процедур для последовательной отправки данных из одной программы в другую.

В этом примере я создаю канал типа bool ch . Невозможно точно сказать, какая строка 9-го и 11-го будет исполнена первой. sendq - это список подпрограмм, ожидающих записи на канал. В этом случае основная ( func main ) подпрограмма ожидает выполнения строки с номером 9.

enter image description here

Еще один пример, когда у нас тупик. Выполнение никогда не перейдет на 8-ю строку, поэтому никогда не будет запущена процедура (следующая строка), в которой я пытаюсь записать данные в канал.

enter image description here

Более подробную информацию о каналах вы можете найти здесь: http://dmitryvorobev.blogspot.com/2016/08/golang-channels-implementation.html

Существует такой термин, как планирование m: n. Golang имеет планировщик m: n, который на m goroutines может планироваться в n потоках ОС планировщиком Go. https://medium.com/@riteeksrivastava/a-complete-journey-with-goroutines-8472630c7f5c

Рекомендую просмотреть эту книгу: https://www.amazon.com/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440. На мой взгляд, это лучшая книга о Голанге, в которой дается описание многих концепций и особенностей этого языка.

О разнице между параллелизмом и параллелизмом вы можете прочитать здесь: https://www.ardanlabs.com/blog/2018/12/scheduling-in-go-part3.html

0 голосов
/ 12 января 2019

Цитата от https://tour.golang.org/concurrency/2:

По умолчанию отправляет и получает блок, пока другая сторона не будет готова. Это позволяет goroutines синхронизироваться без явных блокировок или условные переменные.

Каналы предназначены для работы между программами, но у вас есть только 1. Так что c1 <- 10 блокирует выполнение, пока кто-то (обычно в другой программе) не получит значение.

Чтобы это исправить:

package main

import (
    "fmt"
)

func main() {
    c1 := make(chan int)

    go func() {
        g1 := <- c1 // wait for value
        fmt.Println("get g1: ", g1)
    }()

    fmt.Println("push c1: ")
    c1 <- 10 // send value and wait until it is received.
}

Попробуйте выполнить его в Игровая площадка Go .

Предлагаю вам пройти официальный параллельный тур Go, начиная с https://tour.golang.org/concurrency/1

РЕДАКТИРОВАТЬ: Другой вариант заключается в использовании буферизованного канала, как показано ниже. Однако создание буферизованного канала не означает, что он имеет неблокирующие операции отправки / получения. Это просто означает, что он заблокирует отправку после N значений в очереди, где N всегда предопределенное число. Внутренне он будет хранить отправленные значения в массиве и блокировать до тех пор, пока значения не будут получены (например, небуферизованный канал), когда этот массив заполнен.

package main

import (
    "fmt"
)

func main() {
    c1 := make(chan int, 1) // buffers 1 value without blocking.
    fmt.Println("push c1: ")
    c1 <- 10
    g1 := <- c1
    fmt.Println("get g1: ", g1)
}

Попробуйте на Игровая площадка Go .

...