asynchronousIO服务器:精简(Ruby)和Node.js. 有什么区别?

我想澄清我的asynchronousIO的概念,非阻塞服务器在处理Node.js时,很容易在概念之下

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); }); 

我知道,当node.js等待setTimeout 2秒时,它可以同时处理另一个请求,一旦2秒过去,它就会调用它的callback函数。

在Ruby世界,瘦服务器呢?

 require 'sinatra' require 'thin' set :server, %w[thin] get '/test' do sleep 2 <---- "success" end 

上面的代码片段使用瘦服务器(非阻塞,asynchronousIO),当与asynchronousIO交谈时,我想询问何时到达sleep 2 ,服务器是否能够在sleep 2的同时服务另一个请求阻止IO。

node.js和sinatra之间的代码是node.js正在写asynchronous的方式(callback方法)ruby是以同步的方式写的(但是在asynchronous的方式下工作是否正确)

如果上面的语句是真的,似乎ruby更好,因为代码看起来更好,而不是在node.js中的一堆callback代码

套件

西纳特拉/薄

如果它是由Sinatra启动的(即使用ruby asynchtest.rb ),则Thin将以线程模式启动,

这意味着你的假设是正确的。 当到达睡眠2时,服务器能够同时服务另一个请求, 但是在另一个线程上。

我会用一个简单的testing来显示这个行为:

 #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 

让我们通过启动三个并发的http请求来testing它(在这里timestampthread-id是观察的相关部分):

在这里输入图像描述 testing表明我们得到了三个不同的线程(每个cuncurrent请求一个),即:

  • 70098572502680
  • 70098572602260
  • 70098572485180

它们中的每一个都同时启动(从执行puts语句可以看出,启动是非常直接的),然后等待( hibernate )十秒钟,然后刷新对客户端(对curl进程)的响应。

更深的理解

引用维基百科 – Asynchronous_I / O : 在计算机科学中,asynchronousI / O或非阻塞I / O是input/输出处理的一种forms,允许其他处理在传输完成之前继续。

上面的testing(Sinatra / thin)实际上表明,可以从curl (客户端)开始第一个请求(服务器),在我们从第一个( 在传输完成之前 )得到响应之前,有可能开始第二个和第三个请求,这些最后的请求不会排队,而是同时启动第一个或换句话说: 允许其他处理继续*

基本上这是@Holger的确认只是评论: 睡眠阻止当前线程,但不是整个过程。 这就是说,在很多情况下,大多数东西都是在主反应器线程中处理的,因此类似于node.js中的一个线程:如果阻塞它,则此线程中没有其他任何计划将运行。 在thin / eventmachine中,你可以把东西推迟到其他线程。

这个链接的答案有更多的细节:“ is-sinatra-multi-threaded和单线程仍然处理并发请求?

Node.js的

为了比较两个平台的性能,我们在node.js上运行等价的asynchtest.js ; 正如我们在asynchtest.rbasynchtest.rb那样,我们会在处理开始时添加一个日志行; 这里是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); }); 

让我们在nodejs中启动三个并发请求,并观察相同的行为:
在这里输入图像描述

当然与我们在前面的案例中看到的非常相似。

对于这个非常复杂的问题,这个答复并不是完整的,值得进一步的研究和具体的证据,然后才能为自己的目的得出结论。

有很多细微的差别,几乎太多,在这里列出。

首先,不要混淆“编码风格”和“事件模型”。 没有理由需要在Node.js中使用callback(请参阅各种“承诺”库)。 如果像callback结构化代码一样,Ruby有EventMachine 。

其次,Thin(和Ruby)可以有许多不同的多任务模型。 你没有指定哪一个。

  • 在Ruby 1.8.7中,“线程”将创build绿色线程 。 该语言实际上将一个“睡眠N”变成一个定时器调用,并允许执行其他语句。 但是它有很多限制。
  • Ruby 1.9.x可以创build本地操作系统线程。 但那些可以很难使用(旋转1000年是不利于性能等)
  • Ruby 1.9.x具有“ Fibers ”,这是一个更好的抽象,非常类似于Node。

任何比较,你也必须考虑到整个生态系统:几乎任何node.js代码将在callback中工作。 编写阻止代码真的很难。 但是,很多Ruby库不是开箱即用的线程(需要特殊的configuration等)。 许多看似简单的事情(DNS)可能会阻止整个ruby进程。

你也需要考虑语言。 Node.JS是build立在JavaScript的基础之上的,它有很多黑暗的angular落可以让你起来。 例如,很容易假设JavaScript具有整数,但它不是。 ruby有更less的黑暗angular落(如元编程)。

如果你真的进入了体系结构,那么你应该考虑Go 。 它具有世界上最好的结构:和Node一样,除了支持多处理器外,没有callback(就像在Ruby中一样),还有一stream的消息传递(非常类似于Erlang )。 作为奖励,它将使用Node或Ruby进程的一小部分内存。

不,node.js是完全asynchronous的,setTimeout不会阻止脚本执行,只是延迟它的内部。 所以这部分代码是不相等的。 为您的项目select平台取决于您想要达到的任务。

Interesting Posts