D
David Masover
I am writing something which I am calling "suits" for now -- the idea
being "something you make with threads". It's a lightweight actor model.
Works something like this:
s = Suit.new([])
s.push(1,2,3,4,5) # asynchronous, so ignoring the return value
s[2].now # returns 3
s.length.then{|l| puts l} # prints 5, at some point
s.join # reap the thread
The idea is simple: Map Ruby's object model onto the actor model. (Actually, I
didn't know I was doing actors until I found Revactor -- I just knew it was
vaguely Erlang-inspired.) Therefore, an actor simply looks and feels like an
object, and message-passing is done through Ruby method calls (which are sort
of message passing anyway).
My motivation is to at least make multithreaded Ruby an attractive option, so
that there is a motivation to remove the Python-esque Global Interpreter
Lock. I don't believe separate Unix processes will scale well enough.
There are a few design issues, and I think I'm out of my league here.
Three problems:
First, while I like the syntax of "now" vs "then", it does require some
discipline if you were expecting this to behave like the object it's
referring to. It also means I can't drop a Suit-wrapped object into something
expecting the original.
But making things asynchronous by default would force developers to be aware
of how synchronous (or not) they're actually being.
So, should this be synchronous by default? (Right now, it's not.) Maybe I
should return a "promise" instead, so that things are asynchronous until you
actually need information out of the returned value.
Second, for asynchronous calls, since I'm using a Queue, things arrive
in-order. Would there be an advantage to not requiring that behavior?
Intuitively, I think there would be times when random delivery would be an
asset, but I can't justify it. About the only reason for attempting random
delivery would be to force the programmer to think about multiple threads
sending messages simultaneously.
And finally, what about exception handling? Right now, exceptions will be
delivered on #join, but that requires explicitly checking for them. The thing
that I love about exceptions in a single-threaded app is that unless you do
something special, the exception kills your program. I would much prefer the
behavior to be similar to that, rather than trying to return an exception.
I kind of like how exception handling is done in Erlang, in which
one "process" (think: actor) is responsible for handling the errors of
another. But I'm not sure what the simplest way of doing that in Ruby would
be.
being "something you make with threads". It's a lightweight actor model.
Works something like this:
s = Suit.new([])
s.push(1,2,3,4,5) # asynchronous, so ignoring the return value
s[2].now # returns 3
s.length.then{|l| puts l} # prints 5, at some point
s.join # reap the thread
The idea is simple: Map Ruby's object model onto the actor model. (Actually, I
didn't know I was doing actors until I found Revactor -- I just knew it was
vaguely Erlang-inspired.) Therefore, an actor simply looks and feels like an
object, and message-passing is done through Ruby method calls (which are sort
of message passing anyway).
My motivation is to at least make multithreaded Ruby an attractive option, so
that there is a motivation to remove the Python-esque Global Interpreter
Lock. I don't believe separate Unix processes will scale well enough.
There are a few design issues, and I think I'm out of my league here.
Three problems:
First, while I like the syntax of "now" vs "then", it does require some
discipline if you were expecting this to behave like the object it's
referring to. It also means I can't drop a Suit-wrapped object into something
expecting the original.
But making things asynchronous by default would force developers to be aware
of how synchronous (or not) they're actually being.
So, should this be synchronous by default? (Right now, it's not.) Maybe I
should return a "promise" instead, so that things are asynchronous until you
actually need information out of the returned value.
Second, for asynchronous calls, since I'm using a Queue, things arrive
in-order. Would there be an advantage to not requiring that behavior?
Intuitively, I think there would be times when random delivery would be an
asset, but I can't justify it. About the only reason for attempting random
delivery would be to force the programmer to think about multiple threads
sending messages simultaneously.
And finally, what about exception handling? Right now, exceptions will be
delivered on #join, but that requires explicitly checking for them. The thing
that I love about exceptions in a single-threaded app is that unless you do
something special, the exception kills your program. I would much prefer the
behavior to be similar to that, rather than trying to return an exception.
I kind of like how exception handling is done in Erlang, in which
one "process" (think: actor) is responsible for handling the errors of
another. But I'm not sure what the simplest way of doing that in Ruby would
be.