A possible API may look like this:
class Foo(Monitor):
# Don't need @monitormethod - our caller already handles that
def handle_start(self, source):
b = Bar(self) # Pass them self so they can use our threadpool
self.sendto(b, "greeting", "hello")
def handle_reply(self, source, msg):
print(msg)
class Bar(Monitor):
def handle_greeting(self, source, word):
self.sendto(source, "reply", word + " world")
This is a bit crude (very limited pattern matching), but it's only an
example - Candygram[1] provides some other ideas.
This works best for internal communication (such as a simulation or a
game) that doesn't need to call into libraries that use normal
blocking function calls. An API could be provided for sockets, but
they'd have to be used in a synchronous fashion anyway, to ensure you
don't consume unbounded amounts of buffer space.
The important thing here is the performance - memory consumption and
task switch cost. Each actor needs only the memory of a monitor and
(if used) a generator, not a kernel thread. Task switching is avoided
by delaying your outgoing messages until the current handler finishes,
at which point the current thread can directly start on one of them.
This doesn't directly handle being distributed. If you modified the
language to allow pickling of generators you could do it, but that
breaks invariants of try/finally and the with-statement (including
safethread's "with branch() as children:"), and I don't know of a good
compromise.
[1] http://candygram.sourceforge.net/
--
Adam Olsen, aka Rhamphoryncus