|
List Info
Thread: Erlang-like Processes
|
|
| Erlang-like Processes |

|
2007-08-27 15:10:02 |
|
All: I've added in the first implementation of Erlang-like processes. It's in the current EM head revision. Unit tests are in tests/test_spawn.rb.
Thanks to James Edward Gray II for looking over the interface and making me realize that the first version really sucked. This one is very nice.
Even if you're not into Erlang, you might have noticed the recent ruby-core discussions about Fibers. These are basically non-scheduled threads intended to achieve lightweight concurrency. Your program is supposed to schedule them, and they run until your code tells them to yield.
Erlang processes are a different approach to the same idea. A "process" is basically a data structure and a message queue. Your program can "spawn" (create) any number of processes (millions, if it wants to), and you can send "messages" to any process at any time. The messages carry parameters and cause the code in the process to execute to completion with the given parameters. Code that executes inside a process can send messages back to the same process or to other processes. Note that when you send a message to a process, the message does not execute immediately, but rather is scheduled for execution at some future time. The send-message call returns immediately.
EM now has essentially the same idea, except that "notify" is used in place of "send," which already has a different meaning in Ruby. Here's an implementation of fibonacci with 25 processes:
EM.run { x = 1 y = 1
25.times { s = EM.spawn { x,y = y,x+y } s.notify }
rslt = EM.spawn { puts "Fibonacci result: #" EM.stop } rslt.notify
}
You could also do the same thing with a single worker process, and notify it 25 times.
This is actually a rather crummy sample because it assumes that the notification of the rslt object will take place after the notifications of the fibonacci processes. On a uniprocessor, that assumption will be valid.
Next steps are: 1) to improve the performance; 2) add message filtering like Erlang has, which will allow you to just dump messages into a queue, and one or processes will respond to it based on parameters of the message; and 3) allow you to send messages to spawned processes that are actually running in other "real" processes, or on different machines.
Comments? Suggestions?
|
| Re: Erlang-like Processes |
  United States |
2007-08-27 16:09:35 |
On Aug 27, 3:10 pm, "Francis Cianfrocca"
<garbageca... gmail.com>
wrote:
> All: I've added in the first implementation of
Erlang-like processes. It's
> in the current EM head revision. Unit tests are in
tests/test_spawn.rb.
>
> Thanks to James Edward Gray II for looking over the
interface and making me
> realize that the first version really sucked. This one
is very nice.
I owe Francis thanks for implement something I just said I
wanted, and
then putting up with all my complaints about it as it grew.
The
results are alread great and he is my hero.
> Next steps are: 1) to improve the performance; 2) add
message filtering like
> Erlang has, which will allow you to just dump messages
into a queue, and one
> or processes will respond to it based on parameters of
the message; and 3)
> allow you to send messages to spawned processes that
are actually running in
> other "real" processes, or on different
machines.
>
> Comments? Suggestions?
My comment is that I'm excited. Thanks!
James Edward Gray II
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-27 20:52:08 |
On 8/28/07, Francis Cianfrocca <garbagecat10 gmail.com> wrote:
> All: I've added in the first implementation of
Erlang-like processes. It's
> in the current EM head revision. Unit tests are in
tests/test_spawn.rb.
>
> Thanks to James Edward Gray II for looking over the
interface and making me
> realize that the first version really sucked. This one
is very nice.
>
> Even if you're not into Erlang, you might have noticed
the recent ruby-core
> discussions about Fibers. These are basically
non-scheduled threads intended
> to achieve lightweight concurrency. Your program is
supposed to schedule
> them, and they run until your code tells them to
yield.
>
> Erlang processes are a different approach to the same
idea. A "process" is
> basically a data structure and a message queue. Your
program can "spawn"
> (create) any number of processes (millions, if it wants
to), and you can
> send "messages" to any process at any time.
The messages carry parameters
> and cause the code in the process to execute to
completion with the given
> parameters. Code that executes inside a process can
send messages back to
> the same process or to other processes. Note that when
you send a message to
> a process, the message does not execute immediately,
but rather is scheduled
> for execution at some future time. The send-message
call returns
> immediately.
>
> EM now has essentially the same idea, except that
"notify" is used in place
> of "send," which already has a different
meaning in Ruby. Here's an
> implementation of fibonacci with 25 processes:
Francis,
This is great. * does little bow*.
Ok so here are my doubts:
1. Are these processes real UNIX/Win32 processes or kinda
lightweight
Erlang processes (which are managed by Erlang VM). As i
understand,
probably second one is true. So can you tell some more
about
implementation? I mean, you are having some scheduler like
ruby green
thread scheduler which does this?
2. On my machine, with code from SVN, following code
produces 1, whats wrong?
require "eventmachine"
EM.run {
x = 1
y = 1
25.times {
s = EM.spawn do
x,y = y, x +y
# so if this is the body of spawned process, then i
think its
natural to think, notify should occur from here. Is my
assumption
flawed? Obviously, 's' is kinda erlang pid of process and
hence
's.notify' would also mean that, send a notification to the
spawned
process. Also, i think, variable scope has to be preserved,
and we
should make sure that, spawned process doesn't have access
to
variables, x and y. Again my assumptions could be flawed,
since i
don't fully understand the implementation. but if we spawn
25 process
and variables x and y are shared between them, then again we
are
creating predicament of threads, aren't we?
end
s.notify
}
# In Erlang, normally there is a receive block in our code
to
indicate block thats going to receive external messages.
here its not
clear that, how "y" is getting populated in new
process. In fact, I
have doubt that, "y" is available in spawned
process, because "y" was
delcared globally in scope or "y" is available
because "some process
passed a message to it".
rslt = EM.spawn {
puts "Fibonacci result: #"
EM.stop
}
rslt.notify
}
>
> You could also do the same thing with a single worker
process, and notify it
> 25 times.
>
> This is actually a rather crummy sample because it
assumes that the
> notification of the rslt object will take place after
the notifications of
> the fibonacci processes. On a uniprocessor, that
assumption will be valid.
>
> Next steps are: 1) to improve the performance; 2) add
message filtering like
> Erlang has, which will allow you to just dump messages
into a queue, and one
> or processes will respond to it based on parameters of
the message; and 3)
> allow you to send messages to spawned processes that
are actually running in
> other "real" processes, or on different
machines.
>
> Comments? Suggestions?
Again a big, thanks for this. Also, can you tell me, which
files under
source tree has implementation code, so i can look under the
hood for
better understanding.
thanks.
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-27 20:54:53 |
On 8/28/07, hemant <gethemant gmail.com> wrote:
> On 8/28/07, Francis Cianfrocca <garbagecat10 gmail.com> wrote:
> > All: I've added in the first implementation of
Erlang-like processes. It's
> > in the current EM head revision. Unit tests are in
tests/test_spawn.rb.
> >
> > Thanks to James Edward Gray II for looking over
the interface and making me
> > realize that the first version really sucked. This
one is very nice.
> >
> > Even if you're not into Erlang, you might have
noticed the recent ruby-core
> > discussions about Fibers. These are basically
non-scheduled threads intended
> > to achieve lightweight concurrency. Your program
is supposed to schedule
> > them, and they run until your code tells them to
yield.
> >
> > Erlang processes are a different approach to the
same idea. A "process" is
> > basically a data structure and a message queue.
Your program can "spawn"
> > (create) any number of processes (millions, if it
wants to), and you can
> > send "messages" to any process at any
time. The messages carry parameters
> > and cause the code in the process to execute to
completion with the given
> > parameters. Code that executes inside a process
can send messages back to
> > the same process or to other processes. Note that
when you send a message to
> > a process, the message does not execute
immediately, but rather is scheduled
> > for execution at some future time. The
send-message call returns
> > immediately.
> >
> > EM now has essentially the same idea, except that
"notify" is used in place
> > of "send," which already has a different
meaning in Ruby. Here's an
> > implementation of fibonacci with 25 processes:
>
> Francis,
>
> This is great. * does little bow*.
>
>
> Ok so here are my doubts:
>
> 1. Are these processes real UNIX/Win32 processes or
kinda lightweight
> Erlang processes (which are managed by Erlang VM). As i
understand,
> probably second one is true. So can you tell some more
about
> implementation? I mean, you are having some scheduler
like ruby green
> thread scheduler which does this?
>
> 2. On my machine, with code from SVN, following code
produces 1, whats wrong?
>
> require "eventmachine"
>
> EM.run {
> x = 1
> y = 1
>
> 25.times {
> s = EM.spawn do
> x,y = y, x +y
> # so if this is the body of spawned process, then
i think its
> natural to think, notify should occur from here. Is my
assumption
> flawed? Obviously, 's' is kinda erlang pid of process
and hence
> 's.notify' would also mean that, send a notification to
the spawned
> process. Also, i think, variable scope has to be
preserved, and we
> should make sure that, spawned process doesn't have
access to
> variables, x and y. Again my assumptions could be
flawed, since i
> don't fully understand the implementation. but if we
spawn 25 process
> and variables x and y are shared between them, then
again we are
> creating predicament of threads, aren't we?
> end
> s.notify
> }
>
> # In Erlang, normally there is a receive block in our
code to
> indicate block thats going to receive external
messages. here its not
> clear that, how "y" is getting populated in
new process. In fact, I
> have doubt that, "y" is available in spawned
process, because "y" was
> delcared globally in scope or "y" is
available because "some process
> passed a message to it".
>
> rslt = EM.spawn {
> puts "Fibonacci result: #"
> EM.stop
> }
> rslt.notify
> }
>
>
> >
> > You could also do the same thing with a single
worker process, and notify it
> > 25 times.
> >
> > This is actually a rather crummy sample because it
assumes that the
> > notification of the rslt object will take place
after the notifications of
> > the fibonacci processes. On a uniprocessor, that
assumption will be valid.
> >
> > Next steps are: 1) to improve the performance; 2)
add message filtering like
> > Erlang has, which will allow you to just dump
messages into a queue, and one
> > or processes will respond to it based on
parameters of the message; and 3)
> > allow you to send messages to spawned processes
that are actually running in
> > other "real" processes, or on different
machines.
> >
> > Comments? Suggestions?
>
> Again a big, thanks for this. Also, can you tell me,
which files under
> source tree has implementation code, so i can look
under the hood for
> better understanding.
>
> thanks.
>
Also, do you have plans to make them run on multiple CPUs
and stuff?
Man, how you are gonna do this with Ruby 1.8? Will it be
necessary to
have ruby1.9 for this?
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-28 06:53:56 |
|
On 8/27/07, hemant < gethemant gmail.com">gethemant gmail.com> wrote:
Ok, hemant, lots of great questions here, let's see if I can answer most of them.
This is a working code sample tested on Ruby 1.8 that produces the expected result:
#------------------------------ require 'rubygems' require 'eventmachine';
x=1 y=1
EM.run
{ 25.times { s = EM.spawn {x,y = y,x+y} s.notify }
t = EM.spawn { EM.stop } t.notify }
puts y #------------------------------
Again, it's not illustrative of how you would write a real program, which would not involve variables like x,y that are visible to every process and every block. A better example would use the capability of passing parameters in messages to processes (the parameters are passed to the #notify method). And of course, in a real EM program, you probably wouldn';t be stopping the reactor loop just to get the result!
Here's a considerably more complex alternative, in which 25 processes are spawned, each with a binding to the next. You notify the first one, passing the initial fibonacci parameters, each subsequent process passes its results to the next process in the chain. The last one prints the result and stops the program:
#------------------------------- require 'rubygems' require 'eventmachine';
EM.run { nextpid = EM.spawn {|x,y| puts "#, #"
EM.stop }
25.times { # variable n is block-local, ensuring that every process # binds to a different value of nextpid. We create the processes # "backwards," so that each one has a reference to the last-created
# one. And we start the chain by notifying the last one we create. n = nextpid nextpid = EM.spawn {|x,y| n.notify( y, x+y )} }
nextpid.notify
( 1, 1 ) } #-------------------------------
There's nothing magical about this implementation, in fact it's almost ridiculously simple. All the magic happens in the standard EM reactor core, which schedules spawned processes to run their code block whenever they have notifications, in exactly the same way that it schedules I/O handlers to run when there are I/O events. There is no concern about thread-locking whatsoever, because a notification runs to completion and is never interrupted by EM. As in Erlang (and also in Ruby
1.9 "Fibers"), the concurrency is co-operative rather than pre-emptive.
As regards the coding style: the block you pass to EM#spawn is the code that executes whenever you "notify" (send a message to) an EM spawned process. You can send any number of messages to a given process. At some point in the future it may make sense to augment this interface so that a programmer can specify different blocks of code in the same process, with a choice being made a runtime which block to run, based on the parameters or something else. But I have a feeling it may just be easier to spawn another process. After all, these processes are nothing more than Ruby objects, so you can easily have millions of them.
The next thing I'm going to add is an Erlang-like ability to specify message "filters." That is, when you spawn a process, you can specify a regex or logical expression on the parameters of a notification. Then you'll be able to say
EM.notify( parameters ). Notice, there is no pid specified as the receiver of the notify! The reactor core will inspect all of the currently-active processes and notify the one(s) whose parameter filter matches the notification.
Multi-machine concurrency: Unless you can convince me otherwise, I believe the right answer to this is to leave EM single-threaded and avoid the thread-locking issues altogether. (EM does currently implement a thread-pool (EventMachine#defer) which operates independently of spawned processes.) You'll be able to take advantage or multi-core or multi-CPU hardware simply by running more instances of your single-threaded program. This will work because spawned processes will soon be able to receive notifications from other running programs, just as in Erlang.
Remember that, like Erlang processes, EM spawned processes have no concept of a return value when they process a notification. They're strictly fire and forget. As you saw in the example above, it's easy to make processes aware of other processes (by passing pids around), so you can simulate the effect of sending replies to messages.
If you really want to use that style, however, EM has another lightweight-concurrency feature called "Deferrable." This is inspired directly by the "deferred" object in Python';s Twisted. EM Deferrable is very useful and very graceful, but rather weird conceptually, so it needs its own documentation (which hasn't been written yet). It ultimately provides the same functionality as spawned processes, but packaged in a way that makes it easier to "return values" to code that invokes lengthy operations. And of course, it also runs without threads.
|
| Re: Erlang-like Processes |

|
2007-08-28 08:48:30 |
On 8/28/07, Francis Cianfrocca <garbagecat10 gmail.com> wrote:
> If you really want to use that style, however, EM has
another
> lightweight-concurrency feature called
"Deferrable." This is inspired
> directly by the "deferred" object in Python's
Twisted. EM Deferrable is very
> useful and very graceful, but rather weird
conceptually, so it needs its own
> documentation (which hasn't been written yet). It
ultimately provides the
> same functionality as spawned processes, but packaged
in a way that makes it
> easier to "return values" to code that
invokes lengthy operations. And of
> course, it also runs without threads.
If you want to see an example of a Deferrable in action,
they figure
prominently in the Swiftiply code, which Francis
contributed, to
handle delivering a file via chunked encoding. It's pretty
neat.
Kirk Haines
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-28 10:11:05 |
On 8/28/07, Kirk Haines <wyhaines gmail.com> wrote:
> On 8/28/07, Francis Cianfrocca <garbagecat10 gmail.com> wrote:
>
> > If you really want to use that style, however, EM
has another
> > lightweight-concurrency feature called
"Deferrable." This is inspired
> > directly by the "deferred" object in
Python's Twisted. EM Deferrable is very
> > useful and very graceful, but rather weird
conceptually, so it needs its own
> > documentation (which hasn't been written yet). It
ultimately provides the
> > same functionality as spawned processes, but
packaged in a way that makes it
> > easier to "return values" to code that
invokes lengthy operations. And of
> > course, it also runs without threads.
>
> If you want to see an example of a Deferrable in
action, they figure
> prominently in the Swiftiply code, which Francis
contributed, to
> handle delivering a file via chunked encoding. It's
pretty neat.
>
>
No no, I fully understand deferable pattern and have seen
and used
Twisted deferable as well. I am using EM more than long
enough for
these sort of things. In fact, sometime back i needed my own
callback
pattern and i implemented it similar to the way, deferables
are
implemented in EventMachine.
But Lets say, one server has to truely handle 10,000
concurrent
connections ( there could be several use cases of this, and
i have my
own like a Comet implementation). So what options one really
have?
Me and my collegues experience says that, EM is really nice,
but as
number of connections gets increased ( or lets say number
of
connections is small, but number of requests from them
increases
exponentially), EM loop gets clogged and request processing
slows
down, So what options, does one have?
We are facing that situation right now. We are hunting down
options
and will surely find a solution.
Also, #defer is just a Ruby green thread and hence doesn't
guarantee
any concurrency at all, apart from different execution
path.
Obviously, multiple processes is one solution, but I am just
worried
about IPC overhead. Thats where erlang processes come into
picture,
because they are as independent as a system process and yet
creating
them and communicating between them is not very costly. We
could have
used Erlang, but our code is full of String handling
functions and
Strings are well just one sort of things, erlang doesn't do
too well.
I am still very excited about interprocess mechanism, that
Francis has
talked about.
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-28 10:22:51 |
On 8/28/07, hemant <gethemant gmail.com> wrote:
> No no, I fully understand deferable pattern and have
seen and used
> Twisted deferable as well. I am using EM more than long
enough for
> these sort of things. In fact, sometime back i needed
my own callback
> pattern and i implemented it similar to the way,
deferables are
> implemented in EventMachine.
True, but there are a lot of people reading this who
probably have
never touched 'em, and there isn't really a lot of
documentation about
them in the EM world right now, so it's a simple bit of real
world
code that someone can go look at to see how it works.
That's all.
> But Lets say, one server has to truely handle 10,000
concurrent
> connections ( there could be several use cases of this,
and i have my
> own like a Comet implementation). So what options one
really have?
>
> Me and my collegues experience says that, EM is really
nice, but as
> number of connections gets increased ( or lets say
number of
> connections is small, but number of requests from them
increases
> exponentially), EM loop gets clogged and request
processing slows
> down, So what options, does one have?
This is an interesting observation. Francis, do you have
any sort of
a feel for how bad this effect is? If I have 10k
concurrent
connections, is there a large overhead cost for handling all
of those?
Thanks,
Kirk Haines
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
| Re: Erlang-like Processes |

|
2007-08-28 12:47:05 |
|
On 8/28/07, hemant < gethemant gmail.com">gethemant gmail.com> wrote:
But Lets say, one server has to truely handle 10,000 concurrent connections ( there could be several use cases of this, and i have my own like a Comet implementation). So what options one really have?
Me and my collegues experience says that, EM is really nice, but as number of connections gets increased ( or lets say number of connections is small, but number of requests from them increases exponentially), EM loop gets clogged and request processing slows
down, So what options, does one have?
Use EventMachine on Linux with epoll support. It will easily handle tens of thousands of connections with no degradation in performance or memory usage.
|
| Re: Erlang-like Processes |

|
2007-08-28 19:08:12 |
Just to acknowledge...
> True, but there are a lot of people reading this who
probably have
> never touched 'em, and there isn't really a lot of
documentation about
> them in the EM world right now, so it's a simple bit of
real world
> code that someone can go look at to see how it works.
That's all.
... that this heads-up was appreciated. I've implemented
handling a
'custom' TCP protocol using EM and the next step was to
consider
EM#defer
Thanks
Mark
> > > But Lets say, one server has to truely handle
10,000 concurrent
> > > connections ( there could be several use
cases of this, and i have my
> > > own like a Comet implementation). So what
options one really have?
> > >
> > > Me and my collegues experience says that, EM
is really nice, but as
> > > number of connections gets increased ( or
lets say number of
> > > connections is small, but number of requests
from them increases
> > > exponentially), EM loop gets clogged and
request processing slows
> > > down, So what options, does one have?
> >
> > This is an interesting observation. Francis, do
you have any sort of
> > a feel for how bad this effect is? If I have 10k
concurrent
> > connections, is there a large overhead cost for
handling all of those?
> >
> >
> > Thanks,
> >
> > Kirk Haines
> > _______________________________________________
> > Eventmachine-talk mailing list
> > Eventmachine-talk rubyforge.org
> > http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
> >
>
_______________________________________________
Eventmachine-talk mailing list
Eventmachine-talk rubyforge.org
http://rubyforge.org/mailman/listinfo/eventmachine-talk
a>
|
|
|
|