test1,test2是两个http请求方法,大家分析下两个请求同时发出,客户端哪个先得到相应? 是间隔20秒,还是几乎同时得到? test1 = function(req, res){
sleep(10); var json={ date:new Date() };
res.render(‘home/test1’, json);
}; test2 = function(req, res){ sleep(30); var json={ date:new Date() };
res.render(‘home/test2’, json); };
var sleep=function(second) { var startTime = new Date().getTime(); while(new Date().getTime() <= second*1000 + startTime) { } }
谁先到就先执行谁,你这个都是在一个线程内,如果两个任务相互冲突,按先来后到执行。不知道这样理解对否
对的,是先来先执行的。 但这里面有异步io的问题。
客户端哪个先得到响应? 是间隔20秒,还是几乎同时得到?
@linzhiqiang 相隔20秒,因为异步io是相当于另起了个线程,不在同一个线程,不需要等待test2执行完才执行,不知道理解对否
@peiweippww 我测试的结果是客户端几乎同时响应。 上面两端代码的执行是间隔20秒, 但是res.render 是异步的,需要在下次事件循环是才能执行。
执行顺序是 加入 先请求test1,紧接着请求test2
1:test1执行()sleep 10秒后,res.render(‘home/test’, json);,此时并没有响应客户端,只是插入到事件队列等候下次事件循环。 2 :执行test2(),sleep 30秒后,res.render(‘home/test2’, json);此时并没有响应客户端,只是插入到事件队列等候下次再输出。 3:nodejs从事件队列中输出第一个请求 4: nodejs从事件队列中输出第二个请求
注意:nodejs是单线程的。 我个人分析。
@peiweippww 关键是看node异步huibu会不会在同一个核内运行,如果是同一个核,那就是同时了,告诉我们结果吧,呵
@linzhiqiang 那就说明node在异步io的时候其实没有开线程,还是同一个线程同一个核在处理,这样效率会高点
@peiweippww 在linux上异步io是用几个线程模拟的。 因为linux对异步io支持的不是很好。
@linzhiqiang 我觉得linux多个线程,但是效果还是单线程可以这样理解,它就是为了保持“单线程”的特性,所以在linux上面,即使开了多个线程,也做了一些特殊处理,为的就是保持“单线程”的特性
@peiweippww 我们写的代码,都是单线程的,nodejs内部实现异步io这一块是借助libev(linux)实现的。 以下是转载:异步io的实现 不幸的是,只有Linux下有这么一种支持,而且还有缺陷(AIO仅支持内核I/O中的O_DIRECT方式读取,导致无法利用系统缓存。参见:http://forum.nginx.org/read.php?2,113524,113587#msg-113587 以上都是基于非阻塞I/O进行的设定。另一种理想的异步I/O是采用阻塞I/O,但加入多线程,将I/O操作分到多个线程上,利用线程之间的通信来模拟异步。Glibc的AIO便是这样的典型http://www.ibm.com/developerworks/linux/library/l-async/。然而遗憾在于,它存在一些难以忍受的缺陷和bug。可以简单的概述为:Linux平台下没有完美的异步I/O支持。 所幸的是,libev的作者Marc Alexander Lehmann重新实现了一个异步I/O的库:libeio。libeio实质依然是采用线程池与阻塞I/O模拟出来的异步I/O。 那么在Windows平台下的状况如何呢?而实际上,Windows有一种独有的内核异步IO方案:IOCP。IOCP的思路是真正的异步I/O方案,调用异步方法,然后等待I/O完成通知。IOCP内部依旧是通过线程实现,不同在于这些线程由系统内核接手管理。IOCP的异步模型与Node.js的异步调用模型已经十分近似。 以上两种方案则正是Node.js选择的异步I/O方案。由于Windows平台和*nix平台的差异,Node.js提供了libuv来作为抽象封装层,使得所有平台兼容性的判断都由这一层次来完成,保证上层的Node.js与下层的libeio/libev及IOCP之间各自独立。Node.js在编译期间会判断平台条件,选择性编译unix目录或是win目录下的源文件到目标程序中。
@linzhiqiang 仔细研究下先,文章不错
res.render
其实至少包括3个调用:读取模板文件 -> 加载变量渲染模板 -> 发送渲染结果,其中步骤2会加入事件队列。如果简单的res.send('发送内容')
,测试结果就会截然不同。