Почему чтение канала с помощью go fmt.Println(<-c) не работает?

package main

import "fmt"

func main() {
    c := make(chan int)
    go fmt.Println(<-c)
    c <- 32
}

У меня есть горутина, которая заблокирована в ожидании значения в канале, и в основной горутине есть запись в канал. Почему происходит тупик?

Мне кажется все должно работать, но происходит тупик

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
0
0
87
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Проблема здесь в том, что аргумент fmt.Println оценивается до запуска новой горутины, а не после. См. страницу Экскурсия по Го. Другими словами, ваш код (в основном) эквивалентен следующему:

val := <-c
go fmt.Println(val)

Это приводит к тупику основного потока, поскольку он ожидает, пока c создаст значение для передачи в fmt.Println в основной горутине. Поскольку горутина остается занятой, она никогда не достигает более поздней строки, где вы фактически отправляете значение в канал.

Вместо этого попробуйте это:

go func() { fmt.Println(<-c) }()

Здесь выполнение функции передается отдельной горутине перед вычислением <-c. Это позволяет основной горутине продолжать работу до тех пор, пока не достигнет c <- 32, чтобы предоставить значение для канала.

Вы создали блокирующий канал (без буфера). Он используется для выполнения «встречи», поэтому и отправитель, и получатель будут готовы обмениваться данными.

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

Одно решение:

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)
    go func() {
        fmt.Println(<-c)
    }()
    c <- 32
}

Go пытается прочитать значение вашей горутины перед ее созданием. Это эквивалентно:

go func(i int) {
  for.Println(i)
}(<-c)

Чтобы иметь блок внутри горутины, вы должны прочитать канал внутри горутины, а не читать его как аргумент для горутины.

go func()
  fmt.Println(<-c)
}

Таким образом, вы сначала вызываете свою горутину, а затем читаете канал.


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

Другие вопросы по теме