Почему невозможно получить возвращаемое значение из горутины, присвоив его переменной?
Запуск goroutine (асинхронно) и получение возвращаемого значения из функции - это по сути противоречивые действия. Когда вы говорите, go
вы имеете в виду «выполнять асинхронно» или даже проще: «Продолжайте! Не дожидайтесь завершения выполнения функции». Но когда вы присваиваете значение, возвращаемое функцией, переменной, вы ожидаете, что это значение будет внутри переменной. Поэтому, когда вы это делаете, x := go doSomething(arg)
вы говорите: «Продолжайте, не ждите функции! Подождите-подождите-подождите! Мне нужно, чтобы возвращаемое значение было доступно в x
var прямо в следующей строке!»
каналы
Самый естественный способ получить значение из горутины - это каналы. Каналы - это каналы, которые соединяют параллельные горутины. Вы можете отправлять значения в каналы из одной горутины и получать эти значения в другую горутину или в синхронной функции. Вы можете легко получить значение из горутины, не нарушающей параллелизма, используя select
:
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
Пример взят из Go By Example
CSP и передача сообщений
Go в большей степени основан на теории CSP . Наивное описание, приведенное выше, можно было бы точно изложить в терминах CSP (хотя я считаю, что это выходит за рамки вопроса). Настоятельно рекомендую ознакомиться с теорией CSP хотя бы потому, что это RAD. Эти короткие цитаты дают направление мышления:
Как следует из названия, CSP позволяет описывать системы в терминах компонентных процессов, которые работают независимо и взаимодействуют друг с другом исключительно посредством обмена сообщениями .
В информатике передача сообщений отправляет сообщение процессу и полагается на процесс и вспомогательную инфраструктуру для выбора и вызова фактического кода для выполнения. Передача сообщений отличается от обычного программирования, в котором процесс, подпрограмма или функция вызываются напрямую по имени.