Приведенный ниже код дает ошибку компиляции, говорящую о неожиданном запуске:
x := go doSomething(arg)
func doSomething(arg int) int{
...
return my_int_value
}
Я знаю, что могу получить возвращаемое значение, если вызову функцию как обычно, без использования горутины. Или я могу использовать каналы и т. Д.
У меня вопрос, почему невозможно получить такое возвращаемое значение из горутины.
go
concurrency
goroutine
Нерв
источник
источник
Ответы:
Строгий ответ - вы можете это сделать. Вероятно, это не лучшая идея. Вот код, который это сделает:
var x int go func() { x = doSomething() }()
Это создаст новую горутину, которая вычислит,
doSomething()
а затем назначит результатx
. Проблема в том, как вы собираетесь использоватьx
горутину из оригинальной? Вы, вероятно, захотите убедиться, что порожденная горутина завершена с ним, чтобы у вас не было состояния гонки. Но если вы хотите это сделать, вам понадобится способ связи с горутиной, и если у вас есть способ сделать это, почему бы просто не использовать его для отправки значения обратно?источник
return
, этоassign
ментПочему невозможно получить возвращаемое значение из горутины, присвоив его переменной?
Запуск 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++ { // Await both of these values // simultaneously, printing each one as it arrives. select { case msg1 := <-c1: fmt.Println("received", msg1) case msg2 := <-c2: fmt.Println("received", msg2) } } }
Пример взят из Go By Example
CSP и передача сообщений
Go в большей степени основан на теории CSP . Наивное описание, приведенное выше, можно было бы точно изложить в терминах CSP (хотя я считаю, что это выходит за рамки вопроса). Настоятельно рекомендую ознакомиться с теорией CSP хотя бы потому, что это RAD. Эти короткие цитаты дают направление мышления:
источник
Идея
go
ключевого слова заключается в том, что вы запускаете функцию doSomething асинхронно и продолжаете текущую горутину, не дожидаясь результата, что-то вроде выполнения команды в оболочке Bash с символом «&» после нее. Если ты хочешь сделатьx := doSomething(arg) // Now do something with x
тогда вам нужно заблокировать текущую горутину до завершения doSomething. Так почему бы просто не вызвать doSomething в текущей горутине? Есть и другие варианты (например, doSomething может отправлять результат в канал, из которого текущая горутина получает значения), но простой вызов doSomething и присвоение результата переменной, очевидно, проще.
источник
Это дизайн, выбранный создателями Go. Там целые много абстракций / API для представления значения асинхронных операции ввода / вывод -
promise
,future
,async/await
,callback
,observable
и т.д. Эти абстракции / API , которые по своей природе связаны с единицей планирования - сопрограммы - и эти абстракции / API , диктуют , как сопрограммы ( или, точнее, возвращаемое значение асинхронного ввода-вывода, представленное ими), может быть составлено .Go выбрал передачу сообщений (также называемых каналами ) в качестве абстракции / API для представления возвращаемого значения операций асинхронного ввода-вывода. И, конечно же, горутины и каналы дают вам составной инструмент для реализации операций асинхронного ввода-вывода.
источник