8
votes

Futures à court-circuit dans le clojure

J'ai deux futurs qui résolvent à booléens. Je veux fondamentalement faire quelque chose comme xxx

mais, avec l'optimisation que l'on se termine d'abord, si c'est vrai, je n'attends pas que le futur futur ait fini; juste aller. Bien sûr, si la valeur est fausse, attendez que le futur futur finisse. Y a-t-il une façon simple de faire cela?


4 commentaires

Dax, faire des valeurs "retour" futures? Non, parce que les futurs ne sont pas des fonctions. Les contrats à terme (aka différés ou promesses) sont résolus avec des valeurs conceptuellement très différentes des fonctions qui renvoient une valeur. Tenez votre esprit autour de la différence et votre problème devrait devenir beaucoup plus clair.


@ Beetroot-Beetroot Oui, je comprends cela. Toutefois, étant donné le manque de réponses sur cette question, je me demande si la réponse est vraiment si claire. Avez-vous quelque chose en tête? J'ai quelques idées, mais la plupart sont assez compliqués et j'espérais une réponse simple à ce qui semble un problème simple. J'ai mis à jour la question avec un libellé plus précis.


Dax, alors que je comprends les contrats à terme en termes généraux, je ne connais pas cette langue particulière. Je pense que la réponse de @ Alextaggart est proche de ce que vous voulez, mais vous devez obtenir les deux promesses (probablement par des appels de fonction) plutôt que de les générer à l'intérieur foo .


Si vous pouvez lire JavaScript, je peux vous montrer en principe comment faire cela. Vous auriez besoin de traduire dans Crojure.


4 Réponses :


4
votes

Dans le cas général, vous pouvez donner la même promesse aux deux livraisons. Par exemple: xxx

appeler (foo) donnera au hasard : a ou : b dès que le Premier livrer se produit; L'autre livrer sera un non-op.

à votre cas spécifique, vous avez besoin de deux booléens être retournés. La seule chose que je puisse penser (et c'est un peu désordonnée) serait d'utiliser une troisième promesse partagée entre les livreurs: xxx

  • Si A délivre true d'abord, le ou est terminé immédiatement.
  • Si A délivre false d'abord, le @A retourne immédiatement, puis bloque sur @b . < / li>
  • Si B délivre true d'abord, le ou est terminé immédiatement.
  • Si a délivre false d'abord, il bloque sur @a .

    invoquer à plusieurs reprises (foo) et vous devez voir les résultats escomptés, en particulier lorsque : ou est vrai , alors parfois : a? ou : B? sera FALSE , mais les deux seront toujours true si Si: ou est false .


2 commentaires

Merci pour l'effort, mais je ne pense pas non plus travailler dans ma situation - je n'ai pas accès au code qui appelle livrer . J'ai mis à jour la question pour que cela soit plus évident.


Le cas commun avec les contrats à terme est que vous souhaitez que les données de toutes, mais peuvent faire le travail en parallèle. Le court-circuit s'écarte de cela. Je suis enclin à dire simplement utiliser ou . L'exécution la plus courte sera lorsque le premier futur devienne true avant le deuxième avenir terminé, l'exécution la plus longue sera lorsque le premier futur devienne false et la seconde prend plus de temps pour Achevée.



1
votes

J'adore cette question. Peut-être que je suis surpris que de voir une nouvelle question qui est si simple. Quoi qu'il en soit, la bave de côté, je penser em> J'ai quelque chose qui fonctionne pour vous

Au lieu de faire. P>

(defn future-some [futures]
  (if (empty? futures)
    false
    (let [realized (filter realized? futures)]
      (if (some deref realized)
        true
        (recur (remove (set realized) futures))))))


2 commentaires

Juste pour contribuer au processus de pensée, la question est venue après avoir lu ceci: Tomasp.net/blog /fsharp-variations-joinads.aspx . Ils ont dû créer une extension spéciale du compilateur pour l'activer, mais à la fin, cela permet non seulement de la correspondance de modèle ci-dessus, mais non seulement sur les bits ASYNC. Je pense que le clojure est le type de langage qui pourrait se prêter à une solution extrêmement élégante au problème.


@DAXFOHL Merci pour le lien. Peut-être qu'un jour, si / quand je sais quoi que ce soit à propos de F # et / ou de monads, je peux apprécier davantage à ce sujet.



0
votes

En supposant que vous ne souhaitez pas interroger les contrats à terme tous les x millis et que vous ne pouvez pas contrôler la création des contrats à terme / threads ou le FN qu'ils exécutissent, la solution est juste pour créer encore plus de threads, chaque fil en attente Pour un avenir:

(defn wait-for-any [& futures]
  (let [how-many-left (atom (count futures))
        p (promise)
        wait-and-notify (fn [f]
                         (fn []
                           (if @f
                             (deliver p true)
                             (when (zero? (swap! how-many-left dec))
                               (deliver p false)))))]
    (dorun (map (comp future-call wait-and-notify) futures))
    @p))

 (defn sleep-and-return [what-to-return sleep-time]
  (future
    (Thread/sleep sleep-time)
    what-to-return))


(time (println (wait-for-any
                (sleep-and-return false 1000)
                (sleep-and-return false 2000)
                (sleep-and-return false 3000)
                (sleep-and-return false 4000)
                (sleep-and-return false 5000))))

>>>false
>>>"Elapsed time: 5000.933906 msecs"

(time (println (wait-for-any
                (sleep-and-return false 1000)
                (sleep-and-return true 2900)
                (sleep-and-return true 3000)
                (sleep-and-return false 4000)
                (sleep-and-return false 5000))))
>>>true
>>>"Elapsed time: 2901.309695 msecs"


0 commentaires

3
votes

Ceci est maintenant possible avec core.async code>, comme décrit dans ma réponse à la nouvelle avec des processus de running de running et comparant leurs retours question. Cette réponse définit thread-and code>; Cette question appelle à thread-ou code>: xxx pré>

test avec (constamment faux) et (constamment vrai): p>

;; prints :foo before returning true
(thread-or #(do (Thread/sleep 3000) true)
           #(do (Thread/sleep 1000) (println :foo)))

;; does not print :foo
(thread-or #(do (Thread/sleep 3000) true)
           #(do (Thread/sleep 7000) (println :foo)))


7 commentaires

Toute chance que cela fonctionne avec Core.Match, de sorte que le prédicat du premier ensemble de résultats correspondant soit ensuite exécuté?


Vous pouvez certainement utiliser Core.Match avec des valeurs renvoyées des canaux, ce ne sont que des valeurs de clojure régulières après tout. Dans un Thread-ou Variante Court-circuit court-circuit de la première valeur de Truthy, vous pouvez simplement renvoyer cette valeur, puis utiliser core.match dessus. Si vous souhaitez faire un thread-and , puis à l'aide de fin d'utilisation.Match sur la première valeur à calculer, vous devez stocker la première valeur renvoyée dans une boucle local (ajoutez-le comme la seconde boucle locale - res1 , disons - avec la valeur initiale nil , puis (RECUR ... (NILL? ) Résultat res1)) , avec ... comme avant).


Bien sûr, vous devrez le retourner à partir de thread-et dans le cas de la véracité. (Sauf si vous voulez câbler votre correspondance dans thread-et ; ou vous pouvez le réécrire afin que vous puissiez transmettre cette logique de l'extérieur en tant que fonction.)


En fait, donnez-moi une minute et je posterai thread-ou ; J'allais réellement le faire à l'origine mais avons fini par coller dans fil-et pour une raison quelconque.


OK, voici thread-ou . Également disponible dans ce Gist .


Incidemment, par écrit les commentaires ci-dessus, j'étais initialement convaincu que c'était à propos de la question autre ; Ensuite, j'ai remarqué que j'avais collé thread-et ici aussi. Désolé pour la confusion.


Et voici un GIST avec un thread-ou (en prenant un Nombre arbitraire de fonctions à appeler) sur la base des promesses.