Ich habe zwei Göroutinen, die unabhängig voneinander Daten produzieren, die sie jeweils an einen Kanal senden. In meiner Haupt-Routine möchte ich jeden dieser Ausgänge konsumieren, so wie sie kommen, aber die Reihenfolge, in der sie eingehen, interessiert mich nicht. Jeder Kanal schließt sich selbst, wenn er seine Ausgabe erschöpft hat. Während die select-Anweisung die einfachste Syntax ist, um Eingaben unabhängig voneinander zu konsumieren, habe ich keinen übersichtlichen Weg gesehen, um jeden einzelnen zu durchlaufen, bis beide Kanäle geschlossen sind.Ausbrechen einer Select-Anweisung, wenn alle Kanäle geschlossen sind
for {
select {
case p, ok := <-mins:
if ok {
fmt.Println("Min:", p) //consume output
}
case p, ok := <-maxs:
if ok {
fmt.Println("Max:", p) //consume output
}
//default: //can't guarantee this won't happen while channels are open
// break //ideally I would leave the infinite loop
//only when both channels are done
}
}
das Beste, was ich denken kann, zu tun, ist die folgende (nur skizziert, haben Fehler kompilieren können):
for {
minDone, maxDone := false, false
select {
case p, ok := <-mins:
if ok {
fmt.Println("Min:", p) //consume output
} else {
minDone = true
}
case p, ok := <-maxs:
if ok {
fmt.Println("Max:", p) //consume output
} else {
maxDone = true
}
}
if (minDone && maxDone) {break}
}
aber das sieht aus wie wäre es nicht haltbar, wenn man mit mehr arbeiten als zwei oder drei Kanäle. Die einzige andere Methode, die ich kenne, besteht darin, einen Timout-Fall in der switch-Anweisung zu verwenden, der entweder klein genug ist, um ein frühes Verlassen zu riskieren, oder zu viel Ausfallzeit in die letzte Schleife injiziert. Gibt es eine bessere Möglichkeit, Kanäle zu testen, die sich in einer SELECT-Anweisung befinden?
Ich würde wahrscheinlich diese 'if' Anweisung in eine lokale Funktion umbrechen. Es wäre weniger Unordnung und der Funktionsname würde dazu beitragen, es offensichtlicher zu machen, was geschah (etwas in dieser Richtung: http://play.golang.org/p/347KZdI_Gs). – Chris
+1 für die nicht-clevere Lösung. Es ist wichtig, diese Kanäle auf Null zu setzen, damit sie keine Zeit verschwenden, aber ich könnte eine separate Variable verwenden, um die Anzahl der offenen Kanäle herunterzuzählen.für n = 2; n> 0; {und dann jedes Mal, wenn Sie einen Kanal auf Null setzen, n--. – Sonia
Aus der Sprachspezifikation: "Da die Kommunikation auf Null-Kanälen niemals fortgesetzt werden kann, wählen Sie mit nur Null-Kanälen und keine Standard-Case-Blöcke für immer." Warum blockiert das Obige nicht für immer? [Edit: Oh warte, yep die Pause wird immer vor der ersten Iteration der Schleife, wo beide sind Null] – voutasaurus