-1

I'm making a Ruby server using the em-websocket gem. When a client sends some message (e.g. "thread") the server creates two different threads and sends two anwsers to the client in parallel (I'm actually studying multithreading and websockets). Here's my code:

EM.run {
  EM::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws|
    ws.onmessage { |msg|
      puts "Recieved message: #{msg}"
      if msg == "thread"
        threads = []
        threads << a = Thread.new {
          sleep(1)
          puts "1"
          ws.send("Message sent from thread 1")
        }
        threads << b = Thread.new{
          sleep(2)
          puts "2"
          ws.send("Message sent from thread 2")
        }
        threads.each { |aThread| aThread.join }
      end

How it executes:

  • I'm sending "thread" message to a server
  • After one second in my console I see printed string "1". After another second I see "2".
  • Only after that both messages simultaneously are sent to the client.

The problem is that I want to send messages exactly at the same time when debug output "1" and "2" are sent.

My Ruby version is 1.9.3p194.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • You are using Ruby 1.9.3-p194 which **has known security vulnerabilities!** You should upgrade to the latest 1.9.3 (currently 1.9.3-p448) or 2.0 (currently 2.0.0-p247) as soon as possible. – Andrew Marshall Jul 04 '13 at 13:54

2 Answers2

0

I think the problem is that you are calling sleep method, passing 1 to the first thread and 2 to the second thread. Try removing sleep call on both threads or passing the same value on each call.

Guillermo Maschwitz
  • 1,066
  • 10
  • 16
  • I've inseted sleep methods for testing multithreading. I want to see that theese threads execute parallely but with different time. How can I do this without sleep method? – Alexey Kalmykov Jul 04 '13 at 13:45
  • you should remove sleep calls because you are affecting the result of the test with those calls. – Guillermo Maschwitz Jul 04 '13 at 13:53
  • If you want to see the time difference between both answers, you could add the current timestamp to each answer. ws.send("something sent at #{Time.now.to_i}") – Guillermo Maschwitz Jul 04 '13 at 13:57
  • OK, but timestamps are identically : `This message sent from thread two at 1372946347 This message sent from thread one at 1372946347` – Alexey Kalmykov Jul 04 '13 at 13:59
  • I think it should be : Time.now.to_f * 1000.0. And this gives different timestamps. Thank you! – Alexey Kalmykov Jul 04 '13 at 14:04
  • Wait; This doesn't make sense.I can't really test this situation: theese messages could be sent parallely or in series. – Alexey Kalmykov Jul 04 '13 at 15:02
  • I think Ruby 1.9 does not have real multithreading. But it Depends of the ruby interpreter you are using (most probably MRI). You should investigate if your ruby interpreter support real multithreading. – Guillermo Maschwitz Jul 04 '13 at 15:57
  • But, after all, sending two messages with threads does not imply that both messages wil be sent at the same time. It means that the instructions on each thread will be executed in different threads. Only that. – Guillermo Maschwitz Jul 04 '13 at 16:15
0

I don't have experience with EM, so take this with a pinch of salt.

However, at first glance, it looks like "aThread.join" is actually blocking the "onmessage" method from completing and thus also preventing the "ws.send" from being processed. Have you tried removing the "threads.each" block?

Edit: After having tested this in arch linux with both ruby 1.9.3 and 2.0.0 (using "test.html" from the examples of em-websocket), I am sure that even if removing the "threads.each" block doesn't fix the problem for you, you will still have to remove it as Thread#join will suspend the current thread until the "joined" threads are finished.

If you follow the function call of "ws.onmessage" through the source code, you will end up at the Connection#send_data method of the Eventmachine module and find the following within the comments:

Call this method to send data to the remote end of the network connection. It takes a single String argument, which may contain binary data. Data is buffered to be sent at the end of this event loop tick (cycle).

As "onmessage" is blocked by the "join" until both "send" methods have run, the event loop tick cannot finish until both sets of data are buffered and thus, all the data cannot be sent until this time.

If it is still not working for you after removing the "threads.each" block, make sure that you have restarted your eventmachine and try setting the second sleep to 5 seconds instead. I don't know how long a typical event loop takes in eventmachine (and I can't imagine it to be as long as a second), however, the documentation basically says that if several "send" calls are made within the same tick, they will all be sent at the same time. So increasing the time difference will make sure that this is not happening.

Jon Cole
  • 51
  • 4
  • Is it possible that the client is not actually being updated fast enough and thinks that they arrive at the same time? Have you tried increasing the difference in sleep time? How does the client display the output? – Jon Cole Jul 04 '13 at 14:27
  • I've used tcpdump utility, and problem is on server side, not client; packages are sent simultaneously – Alexey Kalmykov Jul 04 '13 at 14:55