Der folgende Code gibt einen Kompilierungsfehler mit der Meldung "Unerwartetes Los" aus:
x := go doSomething(arg)
func doSomething(arg int) int{
...
return my_int_value
}
Ich weiß, ich kann den Rückgabewert abrufen, wenn ich die Funktion normal aufrufe, ohne Goroutine zu verwenden. Oder ich kann Kanäle usw. verwenden.
Meine Frage ist, warum es nicht möglich ist, einen solchen Rückgabewert von einer Goroutine abzurufen.
go
concurrency
goroutine
Nerv
quelle
quelle
Antworten:
Die strenge Antwort ist, dass Sie das tun können . Es ist einfach wahrscheinlich keine gute Idee. Hier ist Code, der das tun würde:
var x int go func() { x = doSomething() }()
Dadurch wird eine neue Goroutine erzeugt, die
doSomething()
das Ergebnis berechnet und dann zuweistx
. Das Problem ist: Wie werden Siex
von der ursprünglichen Goroutine verwenden? Sie möchten wahrscheinlich sicherstellen, dass die gespawnte Goroutine damit fertig ist, damit Sie keine Rennbedingung haben. Aber wenn Sie das tun möchten, brauchen Sie eine Möglichkeit, mit der Goroutine zu kommunizieren, und wenn Sie eine Möglichkeit haben, dies zu tun, warum nicht einfach verwenden, um den Wert zurückzusenden?quelle
return
, dies istassign
mentWarum ist es nicht möglich, einen Rückgabewert von einer Goroutine abzurufen, die ihn einer Variablen zuweist?
Goroutine ausführen (asynchron) und Rückgabewert von Funktion abrufen sind im Wesentlichen widersprüchliche Aktionen. Wenn Sie sagen,
go
Sie meinen "asynchron machen" oder noch einfacher: "Weiter! Warten Sie nicht, bis die Funktionsausführung abgeschlossen ist". Wenn Sie jedoch einer Variablen einen Funktionsrückgabewert zuweisen, erwarten Sie, dass dieser Wert in der Variablen enthalten ist. Wenn Sie das tun,x := go doSomething(arg)
sagen Sie: "Weiter, warten Sie nicht auf die Funktion! Warten-warten-warten! Ich brauche einen zurückgegebenen Wert, der inx
var direkt in der nächsten Zeile unten verfügbar ist!"Kanäle
Der natürlichste Weg, einen Wert von einer Goroutine abzurufen, sind Kanäle. Kanäle sind die Rohre, die gleichzeitige Goroutinen verbinden. Sie können Werte von einer Goroutine in Kanäle senden und diese Werte in eine andere Goroutine oder in einer synchronen Funktion empfangen. Sie können leicht einen Wert von einer Goroutine erhalten, die die Parallelität nicht unterbricht, indem Sie
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) } } }
Das Beispiel stammt aus Go By Example
CSP & Message-Passing
Go basiert größtenteils auf der CSP-Theorie . Die naive Beschreibung von oben könnte in Bezug auf CSP genau umrissen werden (obwohl ich glaube, dass dies nicht in Frage kommt). Ich empfehle dringend, sich mit der CSP-Theorie vertraut zu machen, zumindest weil es sich um RAD handelt. Diese kurzen Zitate geben eine Denkrichtung vor:
quelle
Die Idee des
go
Schlüsselworts ist, dass Sie die Funktion doSomething asynchron ausführen und die aktuelle Goroutine fortsetzen, ohne auf das Ergebnis zu warten, ähnlich wie beim Ausführen eines Befehls in einer Bash-Shell mit einem '&' danach. Wenn du willstx := doSomething(arg) // Now do something with x
Dann muss die aktuelle Goroutine blockiert werden, bis doSomething beendet ist. Warum also nicht einfach doSomething in der aktuellen Goroutine aufrufen? Es gibt andere Optionen (z. B. könnte doSomething ein Ergebnis an einen Kanal senden, von dem die aktuelle Goroutine Werte empfängt), aber es ist offensichtlich einfacher, einfach doSomething aufzurufen und das Ergebnis einer Variablen zuzuweisen.
quelle
Es ist eine Design-Wahl von Go-Machern. Es gibt eine ganze Menge von Abstraktionen / APIs , den Wert darzustellen async I / O - Operationen -
promise
,future
,async/await
,callback
,observable
usw. Diese Abstraktionen / APIs sind von Natur gebunden an die Einheit der Terminplanung - Koroutinen - und diese Abstraktionen / APIs diktieren , wie Koroutinen ( oder genauer gesagt, der Rückgabewert der von ihnen dargestellten asynchronen E / A kann zusammengesetzt werden .Go wählte Message Passing (auch bekannt als Channels ) als Abstraktion / API, um den Rückgabewert von asynchronen E / A-Operationen darzustellen. Goroutinen und Kanäle bieten Ihnen natürlich ein zusammensetzbares Tool zum Implementieren asynchroner E / A-Operationen.
quelle