Ich habe zwei Futures, die sich in booleans auflösen. Ich möchte im Grunde so etwas wie
machen %Vor%Aber mit der Optimierung, die zuerst abgeschlossen wird, wenn es wahr ist, warte ich nicht auf das Ende der verbleibenden Zukunft; geh einfach. Wenn der Wert falsch ist, warten Sie natürlich, bis die verbleibende Zukunft beendet ist. Gibt es einen einfachen Weg, dies zu tun?
Im allgemeinen Fall können Sie den beiden Zustellern das gleiche Versprechen geben. Zum Beispiel:
%Vor% Der Aufruf von (foo)
liefert zufällig :a
oder :b
, sobald der erste deliver
auftritt; das andere deliver
wird ein No-Op sein.
Für Ihren speziellen Fall müssen zwei Boolesche Werte zurückgegeben werden. Das einzige, was ich mir vorstellen kann (und es ist ein bisschen unordentlich), wäre ein drittes Versprechen, das zwischen den Zustellern geteilt wird:
%Vor%a
zuerst true
liefert, wird or
sofort beendet. a
zuerst false
liefert, gibt @a
sofort zurück und blockt dann auf @b
. b
zuerst true
liefert, wird or
sofort beendet. a
zuerst false
liefert, blockiert es auf @a
. Wiederholt (foo)
aufrufen und Sie sollten die erwarteten Ergebnisse sehen, insbesondere wenn :or
ist true
, dann manchmal :a?
oder :b?
wird false
, aber beide werden immer true
if :or
ist false
.
Dies ist jetzt möglich mit core.async
, wie in meiner Antwort auf die neue mit Clojure threading lang laufenden Prozesse und vergleichen ihre Rückkehr Frage. Diese Antwort definiert thread-and
; Diese Frage erfordert thread-or
:
Test mit (ständig falsch) und (immer wahr):
%Vor%Beachten Sie auch, dass ein Kurzschluss tatsächlich funktioniert:
%Vor%Ich liebe diese Frage absolut. Vielleicht bin ich überrascht, eine neue Frage zu sehen, die so einfach ist. Wie auch immer, beiseite sabbernd denke ich Ich habe etwas, das für dich arbeiten würde.
Anstatt zu tun:
%Vor%Mach:
%Vor% Der Trick ist zu testen, ob etwas realisiert wird, bevor gefragt wird, ob es true
oder false
ist.
Dies könnte wie folgt auf ein Makro verallgemeinert werden:
%Vor%Und dann benutzt wie:
%Vor% Warte eine Sekunde. Vielleicht verstehe ich dein Problem falsch. Vielleicht möchten Sie die Ausführung blockieren, bis EINER der Futures abgeschlossen ist und true
zurückgibt. In diesem Fall tun Sie die then-Klausel Ihrer if
, ODER beide Ihrer Futures sind fertig und geben weder true
, in denen Falls du die else-Klausel von if
machst. Das ist eine andere Geschichte.
Der erfolgreichste Weg, den ich mir vorstellen kann, ist nicht gerade hübsch, aber auch nicht schrecklich lang:
%Vor% Nun wird loop
verwendet, um wiederholt zu loopen, bis eines von zwei Dingen eintritt: Entweder einer der Futures ist sowohl realisiert als auch true
, in welchem Fall die Schleife mit true
zurückkehrt; oder alle Futures werden realisiert und alle von ihnen false
, in welchem Fall die Schleife mit false
zurückkehrt. Es ist wichtig, die (not ...)
-Ausdrücke am Ende des übergeordneten (and ...)
-Ausdrucks zu haben, damit Sie nicht bei der Überprüfung, ob irgendwelche Futures true
oder false
sind, stecken bleiben, bis sie alle realisiert sind.
Diese neue Lösung könnte verallgemeinert werden als:
%Vor% Und genauso verwendet wie das obige future-or
Beispiel.
Jetzt weiß ich fast nichts über Optimierung. Aber soweit ich das beurteilen kann, ist dies sicherlich nicht so effizient, wie es theoretisch sein könnte, denn sobald eine gegebene Zukunft realisiert ist, besteht keine wirkliche Notwendigkeit, ihren Wert mehr als einmal zu testen. Nun, hier sind zwei Lösungen, die ich mit future-some
betitelt habe. Da sich die zu testenden Futures nach jeder Schleifen-Iteration möglicherweise dynamisch ändern müssen, musste ich sie zu einer Funktion machen. Auf diese Weise ist diese neue Methode analog zu some
, nicht or
. In Naturalien habe ich das Verhalten geändert, um eine Sammlung von Futures zu nehmen (im Gegensatz zu einer variablen Anzahl von einzelnen Argumenten - ein weiterer Unterschied zwischen some
und or
). Eine Lösung überprüft nicht (denke ich):
Hier gibt es eine Menge Details, aber das Wesentliche ist Folgendes: Wenn es keine zu testenden Futures gibt, gibt es false
zurück, ansonsten iteriert es die Liste der Futures und testet, ob irgendwelche von ihnen realisiert werden. Wenn eine Zukunft realisiert wird, und auch Dereferenzierungen in true
, bricht die Iteration ab, um true
zurückzugeben. Wenn eine Zukunft realisiert wird, aber nicht auf true
dereferenziert wird, wird die Iteration mit dem nächsten Element fortgesetzt. Wenn eine Zukunft nicht realisiert ist, wird eine Liste hinzugefügt, die bei der nächsten Rekursion von future-some
verwendet wird.
Und die andere Lösung ist prägnanter, aber etwas weniger optimal:
%Vor%Ähnlich wie das andere, außer dass es zuerst das realisierte herausfiltert, dann testet und dann erneut filtert (dieses Mal invers - um das unrealisierte zu erhalten), wenn es wiederholt werden muss. Diese zweite Filterung ist der ineffiziente Schritt.
Ein Problem mit allen von mir vorgeschlagenen Lösungen ist, dass zukünftige Stornierungen zu Fehlern bei der Dereferenzierung führen würden, wenn sie wahrscheinlich einfach so weitergehen sollten, als ob diese Zukunft falsch wäre. Dies ist lösbar, indem (not (future-cancelled? ...))
-Ausdrücke vor jedem Dereferenzieren in jeden einzelnen (and ...)
-Ausdruck gesetzt werden. Oder, für die Funktionen future-some
, müssten Sie das Prädikat realized?
durch (some-fn (comp not future-cancelled?) realized?)
oder #(and (not (future-cancelled %)) (realized? %))
für schwache Nerven ersetzen.
Nochmals, ernsthaft, danke für diese Frage.
Wenn man davon ausgeht, dass man die Futures nicht alle X millis abfragen will und die Erstellung der futures / threads oder fn, die sie ausführen, nicht kontrollieren kann, besteht die Lösung darin, noch mehr Threads zu erstellen, wobei jeder Thread wartet für eine Zukunft:
%Vor%Tags und Links clojure asynchronous promise future