views:

339

answers:

1

I have the following piece of code:

actor {
  loop {
     react {
       case SomeEvent =>
         //I want to submit a piece of work to a queue and then send a response 
         //when that is finished. However, I don't want *this* actor to block
         val params = "Some args"
         val f: Future[Any] = myQueue.submitWork( params );
         actor {
           //await here
           val response = f.get
           publisher ! response
         }

     }
  }
}

As I understood it, the outer actor would not block on f.get because that is actually being performed by a separate actor (the one created inside the SomeEvent handler).

Is this correct?

+2  A: 

Yes, that is correct. Your outer actor will simply create an actor and suspend (wait for its next message). However, be very careful of this kind of thing. The inner actor is started automatically on the scheduler, to be handled by a thread. That thread will block on that Future (that looks like a java.util.concurrent.Future to me). If you do this enough times, you can run into starvation problems where all available threads are blocking on Futures. An actor is basically a work queue, so you should use those semantics instead.

Here's a version of your code, using the Scalaz actors library. This library is much simpler and easier to understand than the standard Scala actors (the source is literally a page and a half). It also leads to much terser code:

actor {(e: SomeEvent) => promise { ... } to publisher }

This version is completely non-blocking.

Apocalisp
But if I'm sending work to a queue and get a (juc) Future back, how can I avoid blocking in the case where I don't control the queue API (i.e. if I can't re-implement the work queue so that the publisher is given events upon work completing)?
oxbow_lakes
Can you submit arbitrary code to the work queue? If so, you could submit a Unit-valued computation that ends by sending a message to one of your actors. And simply ignore the Future[Unit]
Apocalisp
I've edited the question to make it a bit clearer exactly what I'm calling when I submitWork. Basically no, I can't submit arbitrary runnables/callables. However, I wrote all the code originally, so it looks like I'll just have to make an API change :-)
oxbow_lakes
If the work queue is a Java API that you wrote, consider refactoring it with a Better Future: http://apocalisp.wordpress.com/2008/09/02/a-better-future/
Apocalisp
Also, consider that it might be OK to block in your case. If this system isn't highly concurrent, or if nothing will ever depend on the value in the Future.
Apocalisp
It's written in Scala but I'm "feeling my way" to a large extent, so am still using some juc constructs. I've not found a great resource for learning about scala concurrency other than some simple examples. My main problem is one touched on here (http://unlimitednovelty.com/2009/04/why-i-dont-like-scala.html). Where do you draw the line between actors/messages and methods?
oxbow_lakes
Basically my work "items" have to wait on some resource becoming available, so I cannot avoid blocking at some point. I also want to be able to cancel a previously requested piece of work. I'll ask a separate question on the topic if you want to answer that
oxbow_lakes
Which is here: http://stackoverflow.com/questions/954882/migrating-from-java-concurrency-to-scala-concurrency
oxbow_lakes