0
votes

I have some core.async code with a pipeline of two chans and three nodes :

  • a producer - function that puts values into chan1 with >!! (it's not in a go-block but the function is called from inside a go-loop)

  • a filter - another function that's not in a go-block but is called within a go-loop, which pulls items from chan1 (with <!!), does a test and if the test passes pushes them onto chan2 (with >!!)

  • a consumer - an ordinary loop that pulls n values of chan2 with

This code works as expected when I run it as a simple program. But when I copy and paste it to work within a unit-test, it freezes up.

My test code is roughly

(deftest a-test 
  (testing "blah"  
    (is (= (let [c1 (chan)
                 c2 (chan)                 
                 gen (make-generator c1)
                 filt (make-filter c1 c2)
                 result (collector c2 10) ]
              result)
           [0 2 4 6 8 10 12 14 16 18 20]))
))

where the generator creates a sequence of integers counting up from zero and the filter tests for evenness.

As far as I can tell, the filter is able to pull the first value from the c1, but is blocked waiting for a second value. Meanwhile, the generator is blocking while waiting to push its next value into c1.

But this doesn't happen when I run the code in a simple stand-alone program.

So, is there any reason that the unit-test framework might be interfering or causing problems with the threading management that core.async is providing? Is it possible to do unit-testing on async code like this?

I'm concerned that I'm not running the collector in any kind of go-block or go-loop so presumably it might be blocking the main thread. But equally, I presume I have to pull all the data back into the main thread eventually. And if not through that mechanism, how?

1
Why would you use blocking puts and takes within go-blocks? This is usually a bad idea. - OlegTheCat
I'm not inside a go-block ... I'm inside a function that's called from a go-loop .. but Clojure doesn't seem to let me use <! and >! there. - interstar
Maybe I'm not understanding async. What I want is a separate thread for the generator and filter objects. But I don't mind them blocking their own thread when waiting for the next input or for the output channel to be available. But i'm mystified how I'm finding myself deadlocked here. - interstar
did you try using (async/thread (loop [... instead of (async/go-loop [...? - OlegTheCat
no ... let me have a look ... - interstar

1 Answers

2
votes

While using blocking IO within go-blocks/go-loops isn't the best solution, thread macro may be better fit here. It will execute passed body on separate thread, so you may freely use blocking operations there.