Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Short-circuiting futures in clojure

I've got two futures that resolve to booleans. I basically want to do something like

(if (or @future1 @future2) 
  ...)

but, with the optimization that whichever one finishes first, if it's true, then I don't wait for the remaining future to finish; just go. Of course if the value is false, then wait for the remaining future to finish. Is there a straightforward way of doing this?

like image 577
Dax Fohl Avatar asked Jun 01 '13 01:06

Dax Fohl


1 Answers

In the general case, you can give the same promise to the two deliverers. E.g.:

(defn foo []
  (let [p (promise)]
    (future
      (Thread/sleep (rand-int 1000))
      (deliver p :a))
    (future 
      (Thread/sleep (rand-int 1000))
      (deliver p :b))
    @p))

Calling (foo) will randomly yield :a or :b as soon as the first deliver occurs; the other deliver will be a no-op.

To your specific case, you're requiring two booleans be returned. The only thing I can think of (and it's a bit messy) would be to use a third promise shared between the deliverers:

(defn foo []
  (let [a (promise)
        b (promise)
        link (promise)]
    (future
      (Thread/sleep (rand-int 5000))
      (let [res (rand-nth [true false])]
        (deliver link res)
        (deliver a res)))
    (future
      (Thread/sleep (rand-int 5000))
      (let [res (rand-nth [true false])]
        (deliver link res)
        (deliver b res)))
    {:or (or @link @a @b)  
     :a? (realized? a) 
     :b? (realized? b)
     :link @link
     :a @a 
     :b @b}))
  • If a delivers true first, the or completes immediately.
  • If a delivers false first, the @a returns immediately, then blocks on @b.
  • If b delivers true first, the or completes immediately.
  • If a delivers false first, it blocks on @a.

Repeatedly invoke (foo) and you should see expected results, specifically, when :or is true, then sometimes :a? or :b? will be false, but both will always be true if :or is false.

like image 132
Alex Taggart Avatar answered Nov 08 '22 19:11

Alex Taggart