http.createServer([requestListener])中requestListener函数中代码会产生堵塞现象
发布于 1年前 作者 yunnysunny 1646 次浏览

对于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 看完了之后,我依然无法理解之前的那个堵塞现象发生的原因是什么,请各位大牛指教。

22 回复

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);这句话,整个进程就会被卡住。不知道理解的对不对。

用这个 setImmediate

你自己写了阻塞代码。

当一个request到来时,Event-Loop会将这个Listener回调函数放入执行队列, node中所有的代码都是一个一个从执行队列中拿出来执行的。这些执行都是在工作线程上(Event Loop本身可以认为在一个独立的线程中,我们一般不提这个线程,而将node称呼为一个单线程的执行环境), 既然所有的回调都是在一个工作线程上运行,那么,如果某个回调(listener)耗时太久,会然会阻塞执行队列中其它代码的执行,所以你第二个请求就会被第一个请求阻塞了

如果缓解这个问题呢?注意几个方面:

  1. 尽量少写耗时的同步代码,所有文件,网络操作全部用异步执行,对算法进行尽可能的优化
  2. 如果的确是一个大计算量的操作,也建议分解成一个一个小部分,然后通过process.nextTick, setTimeout这些来分片执行,从而间断的释放CPU时间
  3. 采用Cluster来缓解,也就是多进程模型,当一个进程被阻塞时,其它进程可以继续服务

我能怎么说呢, 你这个while是cpu密集, nodejs适合的场景是io密集, 难道你以为异步就不用消耗cpu

我关心的是node的运行原理,以此作为自己编程的指导。

1.node中怎样写异步操作,你说的网络和文件操作确实是可以用异步执行的,但是除了这两个领域之外的,我自定义的一个函数,怎么写成异步的?对于events.EventEmitter来说,他的on和emit函数,是不是都是在工作线程上进行的,换句话说,是不是使用EventEmitter并不能产生异步效果? 2.使用process.nextTick或者setTimeout的话,他的回调函数应该还是运行在工作线程中的把,这个样子应该只会让堵塞操作延迟发生吧。 3.我其实是想问,在单进程下怎样使某一个耗时操作不堵塞工作线程;我想如果在单个进程中有堵塞操作的话,采用多进程是个治标不治本的策略,极端情况下还会把所有进程都堵塞掉。

我关心的是node的运行原理,以此作为自己编程的指导。我这里是写了一个极端情况,来引出我的问题。

你应该仔细去了解一下nodejs的异步模式,了解一下Event Loop,推荐一篇文章http://blog.csdn.net/resouer/article/details/13004377

这篇文章跟我说的是两个层次的东西。 关于node异步的处理,这里有更底层c++代码的讲解(文章链接:http://www.infoq.com/cn/articles/nodejs-asynchronous-io#3970668-tsina-1-88821-4940258fac58681d93622513463cbd0b ),概括一下,就是: node内部采用一个线程池来处理事件,应有程序调用异步代码的时候,将会在线程池中添加一个事件对象,线程池中处理完成后,将当前事件的状态标志为处理完成,然后node的主线程轮询来获取哪些事件处理完成,将处理完的交给应有程序. 综上所述,问题的关键是能够写出异步的代码来,但是异步的代码怎么写呢?系统自带的文件和网络处理有异步的实现,如果我们自己写一个函数能否也能实现异步呢?

@yunnysunny 嗯 了解你的意思了 如果自己去写异步模块的话 貌似要去了解Libuv了

@yunnysunny 我觉得,让堵塞操作延迟发生,把你需要先解决的回调都解决了不就好了,如果这个堵塞是无法避免的话。 另外,或者可以把这个操作碎片化,让它看起来不是很堵塞。

cpu密集和io密集 的区别是什么?

@showen async 属于什么类型的模块?

@showen 这么说node本身并没有提供接口来完成异步操作

@ggaaooppeenngg async貌似不能满足lz的需求吧 async主要是为了让几个异步函数同步执行而不需要去嵌套

@yunnysunny 貌似没有 楼上所说的async模块你可以去看看 也可以看看别人提供的异步模块是如何实现的嘛

@ggaaooppeenngg cpu密集就是指大量 CPU 时间都用于进行计算 io密集是指CPU 占用的大多数时间都是处于 I/O wait 状态

@showen 我要的是异步而不是同步,async从名字上判断很明显是同步。

@showen 好吧,是我自己弄错了,async就是异步的意思

@showen 我看了一下async,它内部就是用setImmediate实现所谓的异步,但是这个函数如果其内部函数是堵塞代码的话,依然会堵塞当前进程。

@yunnysunny setImmediate 是不是说把这个函数放在这个栈的上一个栈执行的意思?

回到顶部