对于http.createServer([requestListener]),我们最常用的用法无怪乎: http.createServer(function(request, response) { //针对不同url的处理代码 }); 这里假设在某个url A对应处理代码中很耗时,这时候你请求A地址的时候肯定会使浏览器处于一直加载状态,这时候你再打开一个页面,然后去请求url B,假设B地址的代码仅仅是现实一个静态页,然后你会发现B地址也处于一直加载状态,也就是说对于url A的耗时处理代码把整个node进程都给堵塞了。 但是我看了一下node中的文档: http.createServer([requestListener])# Returns a new web server object.
The requestListener is a function which is automatically added to the ‘request’ event. 人家说requestListener会被添加到request事件中。http.createServer会返回一个http.Server,而这个类继承自EventEmitter,含有request事件监听。对于这个request事件,文档中是这么写的: Event: 'request’# function (request, response) { }
Emitted each time there is a request. Note that there may be multiple requests per connection (in the case of keep-alive connections). request is an instance of http.IncomingMessage and response is an instance of http.ServerResponse 看完了之后,我依然无法理解之前的那个堵塞现象发生的原因是什么,请各位大牛指教。
var events = require(‘events’);
var em = new events.EventEmitter();
em.on('request’,function(type) {
console.log(‘request:’ + type);
if (type == 1) {
var now = new Date().getTime();
while(new Date().getTime() < now + 1000*3600) {
// do nothing
}
} else if (type == 2) {
} else {
console.log(‘unspport type:’ + type);
}
});
em.emit('request’,2); em.emit('request’,1); em.emit('request’,3);
我模拟了一下,情形大概是这个样子,如果加入em.emit('request’,1);这句话,整个进程就会被卡住。不知道理解的对不对。
当一个request到来时,Event-Loop会将这个Listener回调函数放入执行队列, node中所有的代码都是一个一个从执行队列中拿出来执行的。这些执行都是在工作线程上(Event Loop本身可以认为在一个独立的线程中,我们一般不提这个线程,而将node称呼为一个单线程的执行环境), 既然所有的回调都是在一个工作线程上运行,那么,如果某个回调(listener)耗时太久,会然会阻塞执行队列中其它代码的执行,所以你第二个请求就会被第一个请求阻塞了
如果缓解这个问题呢?注意几个方面:
- 尽量少写耗时的同步代码,所有文件,网络操作全部用异步执行,对算法进行尽可能的优化
- 如果的确是一个大计算量的操作,也建议分解成一个一个小部分,然后通过process.nextTick, setTimeout这些来分片执行,从而间断的释放CPU时间
- 采用Cluster来缓解,也就是多进程模型,当一个进程被阻塞时,其它进程可以继续服务
1.node中怎样写异步操作,你说的网络和文件操作确实是可以用异步执行的,但是除了这两个领域之外的,我自定义的一个函数,怎么写成异步的?对于events.EventEmitter来说,他的on和emit函数,是不是都是在工作线程上进行的,换句话说,是不是使用EventEmitter并不能产生异步效果? 2.使用process.nextTick或者setTimeout的话,他的回调函数应该还是运行在工作线程中的把,这个样子应该只会让堵塞操作延迟发生吧。 3.我其实是想问,在单进程下怎样使某一个耗时操作不堵塞工作线程;我想如果在单个进程中有堵塞操作的话,采用多进程是个治标不治本的策略,极端情况下还会把所有进程都堵塞掉。
这篇文章跟我说的是两个层次的东西。 关于node异步的处理,这里有更底层c++代码的讲解(文章链接:http://www.infoq.com/cn/articles/nodejs-asynchronous-io#3970668-tsina-1-88821-4940258fac58681d93622513463cbd0b ),概括一下,就是: node内部采用一个线程池来处理事件,应有程序调用异步代码的时候,将会在线程池中添加一个事件对象,线程池中处理完成后,将当前事件的状态标志为处理完成,然后node的主线程轮询来获取哪些事件处理完成,将处理完的交给应有程序. 综上所述,问题的关键是能够写出异步的代码来,但是异步的代码怎么写呢?系统自带的文件和网络处理有异步的实现,如果我们自己写一个函数能否也能实现异步呢?