score:9

Accepted answer

it is true that for a pure event-based actor, its reacting code runs on the same thread as message sending code.

but in scala, since it's not desirable to block a thread when an actor calls a blocking operation inside its react code and to unify event-based and thread-based actors(being able to compose them), both type of actors uses the same thread pool but the thread-based actors get their own threads whereas event-based actors shares threads based on a task queue. for details, please see actors that unify threads and events by philipp haller and martin odersky

score:3

the scheduler library uses a thread pool to control execution of the actors. i don't know the specifics of the logic it uses, but, to me, it would seem natural to expect it to:

  • initialize with more than one thread in the pool, as multithreaded applications are very likely to use more than one thead.

  • select the thread to be used with a waiting actor in a queue-like manner -- threads are freed to the end of the queue, and acquire from the beginning of the queue.

also, i assume some threads are used to handle the scheduling itself as well as message passing.

score:4

to see the effect described in the previous answers, you need to generate more than two threads. this sample program generates 100 threads with receive and 100 threads with react.

when you run it, you can see that the receive actors each occupy a thread, and the react ones share a small number of threads. (it's easiest to see when you sort the output.)

import scala.actors._
import scala.actors.actor._

class reactactor extends actor {
  def act {
    loop {
      react {
        case 'hello => println("react: " + thread.currentthread)
      }
    }
  }
}

class receiveactor extends actor {
  def act {
    while (true) {
      receive {
        case 'hello => println("receive: " + thread.currentthread)
      }
    }
  }
}

object main {
  def main(args: array[string]) {
    val count = 100
    val as = new array[actor](2 * count)
    for (i <- 0 until count) {
      as(i) = new reactactor 
      as(count + i) = new receiveactor
    } 
    for (a <- as) a.start()
    actor {
      println(thread.currentthread)
      for (a <- as) a ! 'hello
    }
  }
}

the sorted output in a typical program run:

thread[thread-102,5,main]
react: thread[thread-102,5,main]
react: thread[thread-102,5,main]
react: thread[thread-102,5,main]
...
react: thread[thread-102,5,main]
react: thread[thread-103,5,main]
react: thread[thread-103,5,main]
...
react: thread[thread-103,5,main]
react: thread[thread-104,5,main]
react: thread[thread-104,5,main]
react: thread[thread-104,5,main]
...
react: thread[thread-104,5,main]
react: thread[thread-105,5,main]
react: thread[thread-105,5,main]
react: thread[thread-105,5,main]
...
react: thread[thread-105,5,main]
receive: thread[thread-1,5,main]
receive: thread[thread-10,5,main]
receive: thread[thread-100,5,main]
receive: thread[thread-101,5,main]
receive: thread[thread-11,5,main]
receive: thread[thread-12,5,main]
receive: thread[thread-13,5,main]
receive: thread[thread-14,5,main]
receive: thread[thread-15,5,main]
receive: thread[thread-16,5,main]
receive: thread[thread-17,5,main]
receive: thread[thread-18,5,main]
receive: thread[thread-19,5,main]
receive: thread[thread-2,5,main]
receive: thread[thread-20,5,main]
receive: thread[thread-21,5,main]
...

score:5

don't assume a separate thread per actor. the scala machinery creates a pool of worker threads and only grows that pool if the size of 'blocked' actors is greater than the pool size. when your actor calls receive, it's in a blocked state until it receives its message.


Related Query

More Query from same tag