Sinatra / Thin
Thin
将以线程模式启动,如果它是由Sinatra启动的(即使用ruby asynchtest.rb
)。
这意味着您的假设是正确的;当到达sleep 2时,服务器能够同时处理另一个请求,但在另一个线程上。
我想用一个简单的测试来展示这种行为:
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请求来测试它(在这里,时间戳和线程ID是需要观察的相关部分):
测试表明我们得到了三个不同的线程(每个并发请求一个),即:
- 70098572502680
- 70098572602260
- 70098572485180
它们每个都同时开始(正如我们可以从puts
语句的执行中看到的那样),然后等待(休眠)十秒钟,在那段时间之后将响应刷新到客户端(curl进程)。
更深入的理解
引用维基百科的一句话:异步I/O或非阻塞I/O是一种输入/输出处理方式,允许在传输完成之前进行其他处理。
上面的测试(Sinatra/thin)实际上证明了可以从curl
(客户端)向thin
(服务器)发起第一个请求,并且在我们获得第一个响应之前(在传输完成之前)可以启动第二个和第三个请求,这些最后的请求不会排队,而是同时启动第一个请求,或者换句话说:允许其他处理继续运行*
基本上,这是对@Holger的评论的证实:sleep会阻塞当前线程,但不会阻塞整个进程。也就是说,在thin中,大部分工作都在主反应器线程中处理,因此它的工作方式类似于node.js中可用的一个线程:如果你阻塞了它,那么在该线程中安排的其他所有任务都将停止运行。在thin/eventmachine中,你可以将东西推迟到其他线程。
这些链接的答案有更多细节:“is-sinatra-multi-threaded”和“Single thread still handles concurrency request?”
Node.js
为了比较这两个平台的行为,让我们在node.js上运行一个等效的asynchtest.js
;正如我们在asynchtest.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);
});
让我们在Node.js中启动三个并发请求并观察相同的行为:
![enter image description here](https://istack.dev59.com/5UtwC.webp)
当然,与我们在先前情况下看到的非常相似。
这个响应并不打算在这个非常复杂的主题上详尽无遗,它值得进一步研究和具体证据,以便在自己的目的之前得出结论。