addressalign-toparrow-leftarrow-rightbackbellblockcalendarcameraccwcheckchevron-downchevron-leftchevron-rightchevron-small-downchevron-small-leftchevron-small-rightchevron-small-upchevron-upcircle-with-checkcircle-with-crosscircle-with-pluscontroller-playcredit-cardcrossdots-three-verticaleditemptyheartexporteye-with-lineeyefacebookfolderfullheartglobe--smallglobegmailgooglegroupshelp-with-circleimageimagesinstagramFill 1launch-new-window--smalllight-bulblinklocation-pinm-swarmSearchmailmessagesminusmoremuplabelShape 3 + Rectangle 1ShapeoutlookpersonJoin Group on CardStartprice-ribbonprintShapeShapeShapeShapeImported LayersImported LayersImported Layersshieldstartickettrashtriangle-downtriangle-uptwitteruserwarningyahoo

Actors library: receive vs. react

From: Nathan H.
Sent on: Wednesday, April 1, 2009 10:56 PM
In Monday's meeting Dustin mentioned that in his own testing with many actors making an HTTP request, many (too many) threads were created for receive but it seemed like none or two few were created for react. (Please correct me if I've misstated.) React is supposed to lower the required number of expensive OS-level threads, but at the same time it is expected to distribute the workload among actors and across available processors. I did a little test to better familiarize myself with the two options, using a fibonacci numbers implementation from somewhere on the web.

def fib_tr( n: Int, b: Int, a: Int): Int = n match {
  case 0 => a 
  case _ => fib_tr( n -1, a + b, b)
}

def fib(n:Int) = fib_tr( n, 1, 0) 

import scala.actors._
import scala.actors.Actor._

def test(n: Int) = {
  val s_time = System.currentTimeMillis
  val all = (0 to n) map { n => actor {
    receive {  case _ => println(n); fib(Math.MAX_INT); println(System.currentTimeMillis - s_time); 1  } 
  } }
  all foreach { _ ! "foo"}
  // all
}

You can paste this into the Scala interpreter. I've tried it with values of n from 10 to 50. The surprising thing for me is that even with receive it does not immediately create n threads, though start is called for every actor by the `actor` factory method, before any actors are sent messages. In my process monitory, 6 threads are created after calling test. The actors are brought to life roughly 3 at a time. As actors finish they are garbage collected and the threads are freed, so that the total thread count remains steady until processing is complete; at that point, 2 threads are freed.

To exercise both processor cores on my system I found that values of n greater than 10 are necessary. Whether it's the library, JVM, or OS, something is holding back on distributing threads across cores for at least a few seconds, and then both cores are fully used and the aggregate idle drops to 0%.

With these apparent optimizations of receive, react does not behave any differently for this case. It creates the same number of threads and frees the same number when all processing has been completed. It scales out to both cores in about the same amount of time, and completes in about the same span. But as far as "is react working, despite its low thread count?", it is. With processing intensive actors it will make use of all available processors, the same as receive.

Of course, receive really is different from react and to see that you can uncomment the last expression of `test` so that `all` is returned to the interpreter. With that change, the actors can not be garbage collected as they complete their work and they will retain their threads. That will be one thread for all n actors with receive, plus a few other threads. React only uses and retains the same 7 threads as before. In either case, the background actors make the interpreter a little stubborn about exiting (ctrl+c).

Nathan

People in this
Meetup are also in:

Sign up

Meetup members, Log in

By clicking "Sign up" or "Sign up using Facebook", you confirm that you accept our Terms of Service & Privacy Policy