4

I wanna clear my concept of asynchronous IO, non-blocking server When dealing with Node.js , it is easy to under the concept

var express = require('express');
var app = express();

app.get('/test', function(req, res){
  setTimeout(function(){
    console.log("sleep doesn't block, and now return");
    res.send('success');
  }, 2000);
});

var server = app.listen(3000, function() {
  console.log('Listening on port %d', server.address().port);
});

I know that when node.js is waiting for 2 seconds of setTimeout, it is able to serve another request at the same time, once the 2 seconds is passed, it will call it callback function.

How about in Ruby world, thin server?

require 'sinatra'
require 'thin'
set :server, %w[thin]

get '/test' do
  sleep 2   <----
  "success"
end

The code snippet above is using Thin server (non-blocking, asynchronous IO), When talking to asynchronous IO, i want to ask when reaching sleep 2 , is that the server are able to serve another request at the same time as sleep 2 is blocking IO.

The code between node.js and sinatra is that node.js is writing asynchronous way (callback approach) ruby is writing in synchronous way (but working in asynchronous way under the cover? is it true)

If the above statement is true, it seems that ruby is better as the code looks better rather than bunch of callback code in node.js

Kit

TheOneTeam
  • 25,806
  • 45
  • 116
  • 158

3 Answers3

9

Sinatra / Thin

Thin will be started in threaded mode, if it is started by Sinatra (i.e. with ruby asynchtest.rb)

This means that your assumptions are correct; when reaching sleep 2 , the server is able to serve another request at the same time , but on another thread.

I would to show this behavior with a simple test:

#asynchtest.rb
require 'sinatra'
require 'thin'
set :server, %w[thin]

get '/test' do
  puts "[#{Time.now.strftime("%H:%M:%S")}] logging /test starts on thread_id:#{Thread.current.object_id} \n"
  sleep 10
  "[#{Time.now.strftime("%H:%M:%S")}] success - id:#{Thread.current.object_id} \n"
end

let's test it by starting three concurrent http requests ( in here timestamp and thread-id are relevant parts to observe):

enter image description here The test demonstrate that we got three different thread ( one for each cuncurrent request ), namely:

  • 70098572502680
  • 70098572602260
  • 70098572485180

each of them starts concurrently ( the starts is pretty immediate as we can see from the execution of the puts statement ) , then waits (sleeps) ten seconds and after that time flush the response to the client (to the curl process).

deeper understanding

Quoting wikipedia - Asynchronous_I/O: In computer science, asynchronous I/O, or non-blocking I/O is a form of input/output processing that permits other processing to continue before the transmission has finished .

The above test (Sinatra/thin) actually demonstrate that it's possible to start a first request from curl ( the client ) to thin ( the server) and, before we get the response from the first (before the transmission has finished) it's possible to start a second and a third request and these lasts requests aren't queued but starts concurrently the first one or in other words: permits other processing to continue*

Basically this is a confirmation of the @Holger just's comment: sleep blocks the current thread, but not the whole process. That said, in thin, most stuff is handled in the main reactor thread which thus works similar to the one thread available in node.js: if you block it, nothing else scheduled in this thread will run. In thin/eventmachine, you can however defer stuff to other threads.

This linked answers have more details: "is-sinatra-multi-threaded and Single thread still handles concurrency request?

Node.js

To compare the behavoir of the two platform let's run an equivalent asynchtest.js on node.js; as we do in asynchtest.rb to undertand what happen we add a log line when processing starts; here the code of asynchtest.rb:

var express = require('express');
var app = express();

app.get('/test', function(req, res){
  console.log("[" + getTime() + "] logging /test starts\n");
  setTimeout(function(){
    console.log("sleep doen't block, and now return");
    res.send('[' + getTime() + '] success \n');
  },10000);
});

var server = app.listen(3000,function(){
  console.log("listening on port %d", server.address().port);
});

Let's starts three concurrent requests in nodejs and observe the same behavoir:
enter image description here

of course very similar to what we saw in the previous case.

This response doesn't claim to be exhaustive on the subject which is very complex and deserves further study and specific evidence before drawing conclusions for their own purposes.

Community
  • 1
  • 1
Franco Rondini
  • 10,841
  • 8
  • 51
  • 77
  • thx for the answer. Just wonder, if thin is started with thread mode, we then can't benefit the async non-blocking IO behaviour by thin. As we all know, the benefit of that non-blocking mode is that we can serve any other request at that time if the operation is blocking... – TheOneTeam Aug 24 '14 at 05:09
  • enhanced the answer and linked [more details on thin and Non blocking IOs/Reactor pattern](http://stackoverflow.com/a/25494136/1657028), carefully examining the screenshot of the two test could be helpful – Franco Rondini Aug 25 '14 at 21:12
0

There are lots of subtle differences, almost too many to list here.

First, don't confuse "coding style" with "event model". There's no reason you need to use callbacks in Node.js (see various 'promise' libraries). And Ruby has EventMachine if like the call-back structured code.

Second, Thin (and Ruby) can have many different multi-tasking models. You didn't specify which one.

  • In Ruby 1.8.7, "Thread" will create green threads. The language actually turns a "sleep N" into a timer call, and allows other statements to execute. But it's got a lot of limitations.
  • Ruby 1.9.x can create native OS threads. But those can be hard to use (spinning up 1000's is bad for performance, etc.)
  • Ruby 1.9.x has "Fibers" which are a much better abstraction, very similar to Node.

In any comparison, you also have to take into account the entire ecosystem: Pretty much any node.js code will work in a callback. It's really hard to write blocking code. But many Ruby libraries are not Thread-aware out of the box (require special configuration, etc). Many seemingly simple things (DNS) can block the entire ruby process.

You also need to consider the language. Node.JS, is built on JavaScript, which has a lot of dark corners to trip you up. For example, it's easy to assume that JavaScript has Integers, but it doesn't. Ruby has fewer dark corners (such as Metaprogramming).

If you are really into evented architectures, you should really consider Go. It has the best of all worlds: The evented architecture is built in (just like in Node, except it's multiprocessor-aware), there are no callbacks (just like in Ruby), plus it has first-class messaging (very similar to Erlang). As a bonus, it will use a fraction of the memory of a Node or Ruby process.

BraveNewCurrency
  • 12,654
  • 2
  • 42
  • 50
-1

No, node.js is fully asynchronous, setTimeout will not block script execution, just delay part inside it. So this parts of code are not equal. Choosing platform for your project depends on tasks you want to reach.

monkeyinsight
  • 4,719
  • 1
  • 20
  • 28
  • what about in the ruby /thin world? When calling sleep, will it block the script/ or able to server another request at the same time? – TheOneTeam Aug 15 '14 at 03:19
  • @KitHo yes, ruby's sleep halts whole process – monkeyinsight Aug 15 '14 at 03:30
  • i dont' think so, if yes, how thin can handle concurrent request? – TheOneTeam Aug 15 '14 at 06:47
  • @monkeyinsight That's not true. `sleep` blocks the current thread, but not the whole process. That said, in thin, most stuff is handled in the main reactor thread which thus works similar to the one thread available in node.js: if you block it, nothing else *scheduled in this thread* will run. In thin/eventmachine, you can however defer stuff to other threads. – Holger Just Aug 15 '14 at 15:27
  • @Just, so if using thin, when the code is executing `sleep 2`, are they able to serve another request like Node.js? (since it is non-blocking IO) – TheOneTeam Aug 15 '14 at 16:29