Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Sunday, August 16, 2009

Try EventMachine

The Ruby library EventMachine makes us easy to write a network server/client software on Ruby.

Here's an echo server described in the EventMachine README.

require 'eventmachine'

module EchoServer
  def post_init
    puts "-- someone connected to the echo server!"
  end

  def receive_data data
    send_data ">>>you sent: #{data}"
    close_connection if data =~ /quit/i
  end

  def unbind
    puts "-- someone disconnected from the echo server!"
  end
end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 8081, EchoServer
}

Let's try it. Save the code to a.rb and do the command:

$ rake build
$ ruby -Ilib a.rb

Now the echo server started on port 8081. Let me check it on another terminal.

$ telnet localhost 8081
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying fe80::1...
telnet: connect to address fe80::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hi
>>>you sent: hi
hey
>>>you sent: hey

It certainly worked.

Say server

OSX has say command which speaks the given sentence. Now I'll write Say Server to handle notification from a remote machine.

require 'eventmachine'

module SayServer
  def receive_data(data)
    system 'say', data
    close_connection
  end
end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 8081, SayServer
}

It was too easy to fix it.

Unfortunately I didn't know how to make the server say a word in one line. The following command didn't work like I expected.

$ echo 'hi' | telnet localhost 8081

Spawned Processes

I found an interesting document in docs/SPAWNED_PROCESSES.

Spawned Processes in EventMachine are inspired directly by the "processes" found in the Erlang programming language. EM deliberately borrows much (but not all) of Erlang's terminology. However, EM's spawned processes differ from Erlang's in ways that reflect not only Ruby style, but also the fact that Ruby is not a functional language like Erlang.

Note that the word spawn doesn't mean Kernel.#spawn in ruby 1.9. This EventMachine.spawn generates something like an Erlang's tiny process, which can receive and send a message each other.

Here's sample ping-pong code:

require 'eventmachine'

EM.run {
  pong = EM.spawn {|x, ping|
    sleep 0.1
    puts "Pong received #{x}"
    ping.notify( x-1 )
  }

  ping = EM.spawn {|x|
    if x > 0
      puts "Pinging #{x}"
      pong.notify x, self
    else
      EM.stop
    end
  }

  ping.notify 3
}
p :finished

The result is:

$ ruby -Ilib a.rb
Pinging 3
Pong received 3
Pinging 2
Pong received 2
Pinging 1
Pong received 1
:finished

I expected that the message :finished would appers during the ping-pong, but didn't. I fixed the line 'ping.notify 3' into 'Thread.start { ping.notify 3}', but the result was still same. Even worse, 'fork { ping.notify 3 }' got frozen up.

[Aug 18 Added] Stoyan suggested that EM::Deferrable is suit to be used instead of Thread or spawn. The page he introduced shows the following sample code (I added comments on it a little to show the order of processing)

class Worker
  include EM::Deferrable

  def heavy_lifting
    # (3)
    3.times do |i|
      puts "Lifted #{i}"
      sleep 0.1
    end
    set_deferred_status :succeeded
  end
end

EM.run do
  # (1)
  worker = Worker.new
  worker.callback {
    # (4)
    p "done!"
  }
  Thread.new {
    # (2)
    worker.heavy_lifting
    # (5)
    EM.stop
  }
  # (3)'
  puts "resuming remaining program operations"
end

And the result is

Lifted 0
resuming remaining program operations
Lifted 1
Lifted 2
"done!"

2 comments:

  1. For parallel jobs better try EM::Deferrable, then Thread or spawn. EventMachine is a single threaded, events based. For example: http://nutrun.com/weblog/distributed-programming-with-jabber-and-eventmachine/

    ReplyDelete
  2. Thanks! I added a paragraph about it on this post.

    ReplyDelete

Followers