3 Stimmen

Ist es möglich, ein Ergebnis aus einer Reihe von Goroutinen in Go zu erhalten?

Ich habe erst vor kurzem die Programmiersprache Go von Google kennengelernt. Die angebotene Unterstützung für Gleichzeitigkeit hat mich fasziniert, und ich habe mich daran gemacht, mehr darüber zu erfahren. Ich wollte jedoch sehen, wie Go ein bestimmtes Merkmal der Gleichzeitigkeit implementiert, und bisher habe ich keinerlei Hinweise darauf gefunden, dass dieses Merkmal überhaupt vorhanden ist.

Hier ist eine hypothetische Situation: Nehmen wir an, wir programmieren eine Funktion, die den Foo-Wert einer bestimmten Eingabe bestimmt. Für jede beliebige Eingabe wird der Foo-Wert entweder im Bereich A oder im Bereich B gefunden (nicht in beiden). Die Techniken für die Suche in diesen Bereichen sind recht unterschiedlich, aber sie haben die Eigenschaft, dass erfolgreiche Suchvorgänge in der Regel schnell zu einem Ergebnis führen, während erfolglose Suchvorgänge den gesamten Datensatz durchlaufen müssen, um vollständig zu sein, und daher viel Zeit in Anspruch nehmen.

In anderen Sprachen, die Gleichzeitigkeit verwenden (z. B. Cilk ) könnte man die Funktion Foosearch so programmieren, dass sie eine Asearch-Funktion und eine Bsearch-Funktion auslöst. Diese Funktionen würden gleichzeitig laufen, und immer wenn entweder eine Antwort, so würde diese Antwort der aufrufenden Funktion Foosearch mitgeteilt, die alle von ihr ausgelösten Funktionen, die nicht zurückgekehrt sind, beenden würde.

Bei den Goroutinen von Go sieht es jedoch so aus, als könne man nur zwei Routinen mit einem Kanal verbinden - man könnte also nicht einen Kanal einrichten, an den entweder Asearch oder Bsearch senden könnte, je nachdem, wer zuerst eine Antwort gefunden hat, und Foosearch daraus lesen lassen. Es sieht auch so aus, als ob man nicht von einem Kanal lesen kann, ohne ihn zu blockieren - also könnte man Foosearch nicht Asearch und Bsearch starten und Kanäle von beiden einrichten und dann in einer Schleife laufen lassen, um zu sehen, ob der eine oder der andere eine Antwort produziert hat.

Ist mein Verständnis der Grenzen der Gleichzeitigkeit von Go richtig? Gibt es eine andere Möglichkeit, das angegebene Ergebnis zu erreichen?

16voto

Brian Campbell Punkte 304982

Nein, ich glaube nicht, dass Ihr Verständnis der Grenzen von Go richtig ist.

Zum einen gibt es nichts, was ich in Go gesehen habe, das Kanäle auf die Kommunikation zwischen zwei Routinen beschränkt. Sie können denselben Kanal sowohl an Asearch als auch an Bsearch übergeben, und dann kann diejenige, die die Suche beendet, das Ergebnis auf diesem Kanal senden.

Wenn Sie stattdessen zwei Kanäle verwenden und darauf warten wollen, dass einer von ihnen das Ergebnis liefert, können Sie einfach die Funktion select Erklärung. Von der Zum Lernprogramm Ein Beispiel für die Auswahl eines Kanals, der zum Senden von Anfragen verwendet wird, und eines Kanals, der dazu dient, dem Server das Beenden zu signalisieren:

21    func server(op binOp, service chan *request, quit chan bool) {
22        for {
23            select {
24            case req := <-service:
25                go run(op, req);  // don't wait for it
26            case <-quit:
27                return;
28            }
29        }
30    }

Außerdem können Sie, während Empfänge von einem Kanal normalerweise blockiert werden, auch eine nicht-blockierender Empfang aus einem Kanal.

Wenn ein Empfangsausdruck in einer Zuweisung oder Initialisierung der Form

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch

wird der Empfangsvorgang nicht blockiert. Wenn der Vorgang fortgesetzt werden, wird die boolesche Variable ok auf true gesetzt und der Wert in x gespeichert; andernfalls wird ok auf false gesetzt und x wird auf den Nullwert für seinen Typ gesetzt (§ Der Nullwert ).

Es gibt also mehrere Möglichkeiten, auf das Ergebnis von mehreren Goroutinen zu warten, ohne zu blockieren. Ich denke, ich würde mit mehreren Kanälen multiplexed mit gehen select Denn auf diese Weise können Sie leicht feststellen, welche Routine das Ergebnis zurückgegeben hat, ohne dass Sie diese Information in den Wert packen müssen, den Sie senden, oder eine andere Form der Out-of-Band-Kommunikation durchführen müssen.

5voto

Sie können die select Schlüsselwort, um von mehreren Kanälen zu empfangen.

Der Wert wird von dem Kanal genommen, der das Ergebnis früher als die anderen hat.

var c1, c2 chan int;
var result int;

select {
case result = <-c1:
    print("received ", result, " from c1\n");
case result = <-c2:
    print("received ", result, " from c2\n");
}

Referenz

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X