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: #{y}" 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? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070827/57052031/attachment.html
On Aug 27, 3:10 pm, "Francis Cianfrocca" <garbageca... at 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
On 8/28/07, Francis Cianfrocca <garbagecat10 at 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: #{y}" 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.
On 8/28/07, hemant <gethemant at gmail.com> wrote:> On 8/28/07, Francis Cianfrocca <garbagecat10 at 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: #{y}" > 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?
On 8/27/07, hemant <gethemant at 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 "#{x}, #{y}" 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070828/480ca069/attachment-0001.html
On 8/28/07, Francis Cianfrocca <garbagecat10 at 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
On 8/28/07, Kirk Haines <wyhaines at gmail.com> wrote:> On 8/28/07, Francis Cianfrocca <garbagecat10 at 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.
On 8/28/07, hemant <gethemant at 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
On 8/28/07, hemant <gethemant at 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070828/6a1d8255/attachment.html
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 at rubyforge.org > > http://rubyforge.org/mailman/listinfo/eventmachine-talk > > >
I''m curious if you''ve ever looked at Omnibus, which implements Actors / futures in Ruby, and can tell us how that compares: http://rubyforge.org/projects/concurrent On 8/27/07, Francis Cianfrocca <garbagecat10 at 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: > > EM.run { > x = 1 > y = 1 > > 25.times { > s = EM.spawn { x,y = y,x+y } > s.notify > } > > rslt = EM.spawn { > puts "Fibonacci result: #{y}" > 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? > > _______________________________________________ > Eventmachine-talk mailing list > Eventmachine-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/eventmachine-talk >-- Tony Arcieri ClickCaster, Inc. tony at clickcaster.com 720-227-0129 ext. 202 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070828/b2f0d9e7/attachment.html
On 8/28/07, Mark Van De Vyver <mvyver at gmail.com> wrote:> > > ... 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 > MarkInquiring minds want to know, Mark. What was your experience like, implementing the custom protocol? Any problems or rough spots? EM#defer works with a pool of Ruby threads managed by EM. It''s indispensable for certain things (like making blocking calls to database libraries) but should be avoided for everything else. EM works perfectly well in the presence of Ruby threads, but Ruby''s thread scheduler exacts an INCREDIBLE performance penalty (with or without EM), and you really should avoid threads in performance-sensitive code. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070828/3b2e757a/attachment-0001.html
On 8/28/07, Tony Arcieri <tony at clickcaster.com> wrote:> > I''m curious if you''ve ever looked at Omnibus, which implements Actors / > futures in Ruby, and can tell us how that compares: > > http://rubyforge.org/projects/concurrentI''ve only taken the briefest of looks at this project. Anyone else have anything to report about it? I like Actors. I like ''em so much I actually created a distributed programming language based on them about a dozen years ago. Then Java came along and ate the world, so I got out of the language-design business. ;-) If by "futures," this project refers to that feature from the "Alice" programming language, I think those are really cool too. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070828/ebab9968/attachment.html
On 8/28/07, Kirk Haines <wyhaines at gmail.com> wrote:> On 8/28/07, Francis Cianfrocca <garbagecat10 at 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, Both the following seemed empty. Is there somewhere else I can look for a repo? svn checkout svn://rubyforge.org/var/svn/swiftiply svn checkout http://swiftiply.rubyforge.org/svn/trunk/ Regards Mark> Kirk Haines > _______________________________________________ > Eventmachine-talk mailing list > Eventmachine-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/eventmachine-talk >
On 8/31/07, Mark Van De Vyver <mvyver at gmail.com> wrote:> Both the following seemed empty. Is there somewhere else I can look for a repo? > > svn checkout svn://rubyforge.org/var/svn/swiftiply > svn checkout http://swiftiply.rubyforge.org/svn/trunk/Ah, yeah. http://src.swiftiply.swiftcore.org:8900 is the repository viewer. It''s in Mercurial. Kirk