你不妨先思考一个问题:
在单核时代,PHP之类多线程或者多进程的,是怎么处理并发的?是排队吗?

答案是:的确就是排队。但是并不是一定要处理完请求1才能去处理请求2:实际上请求的处理过程中,有很多的时间是耗在IO等其他地方,这时可以切换去处理其他请求,把等待的时间可以充分利用起来,达到更高的吞吐量。切换调度的策略是线程库,或者OS实现的,由于每个进程/线程需要占用不少资源(典型的是内存,一个线程通常需要2M的栈空间),更重要的是,线程/进程切换时的开销是非常大的。

既然如此,为何不让线程自己来管理呢?于是大家都开始用select/poll了,由于减少了上面说到的开销,吞吐量显著提高。这就是所谓的IO多路复用。但是大家用着用着,发现并发到了一定量级又上不去了怎么办?这就是所谓的c10k problem了。

经查,发现是select用O(n)的效率不断地去查看那些fd,效率太低。于是Linux供出了epoll,bsd供出了kqueue,windows供出了IOCP,通过在内核中提供callback机制的方式,epoll在内部使用RBTree把O(n)降到了O(logn)(感谢鱼丸粗面纠正)。于是并发量就上去了。

大家熟知的libevent/libev基本上就是把不同系统的类似机制封装好,为上层提供一个统一的接口,方便开发和移植。这个还有个装逼的说法叫做reactor模式。

最后回到你的问题,nodejs的确就是排队的。关键在于怎么在排队的时候充分利用插队策略来达到最高的效率。nodejs内部的实现我没有具体了解,不过应当是使用类似协程这样的技术,在需要阻塞的地方,从底层入手引入调度机制,从而使得上层看起来似乎仍然是同步、阻塞的(感谢@TonySeek的指正,nodejs用的是callback套callback的方式,详见评论;我说的那个是python+gevent的实现方式) 。

扩展一下,对于如何充分利用多核来提高效率的问题,答案就是:多开几个进程(补充:这里特指针对单进程而言;而且并不是进程越多越好,一般而言与CPU线程数相当为佳)。

1

node 用的是作者自己开发的 libuv,和 libev/libevent 很相似,只不过在 Windows 下不是用 select 而是用 IOCP。协程只是一种让 callback 扁平化的方式,node 缺的就是这个,callback 套 callback 非常恶心。

#1 TonySeek· 2013年04月23日 · 回复

1

提高效率也不应该简单的总结为多开几个进程,同一任务的线程(进程)数大于处理器支持的物理最大线程数时,不仅不能得到更高的效率,反而会增加调度开销。尤其是 Web 服务器这类 IO 密集型的,一般进程数等于处理器核数就足够。

#2 TonySeek· 2013年04月23日 · 回复

展开评论

答案对人有帮助,有参考价值4答案没帮助,是错误的答案,答非所问
奈文 804 2013年04月17日 回答 · 2013年04月23日 更新

其实现在的异步模型大同小异,大致过程如下(分三层):

1.(最重要的)维护一个事件反应堆,用epoll或者select或者kqueue来做,反应堆的作用就是用同步的方式处理异步问题,在反应堆上注册好事件后如果相应的事件发生,就调用其回调函数,一般情况下反应堆是一个进程内全局唯一的。

2.上层的buffer,维护一系列的buffer用于管理每一个连接的数据,可以把buffer看做是一个对象。一般在一个连接到达的时候分配一个buffer对象,然后上层的连接注册事件的时候是注册到buffer上,buffer再注册到反应堆中。

3.就是一个个的连接对象,把每一个来自外部的连接都抽象为一个具体的对象,用于管理每一个连接,其中这个对象就包含了上面所说的buffer对象和其他一些状态。

处理并发的过程就是这样的:

1.为监听套接口在反应堆注册一个事件,此事件发生调用对应的回调,一般情况是accept这个连接,然后为这个连接创建连接对象,统一管理。

2.为此连接创建buffer对象,并注册对应的读写错误事件的回调(上层对于buffer的读写事件回调都是业务层来控制的了).

3.(所谓的排队机制也不是完全正确)在加入监听队列后是离散的,准确来说epoll中是由一颗红黑树维护的,每一个事件的先后顺序跟它达到的顺序有关。

4.维护了众多的连接对象,也就是这里的并发情况了,如果有事件发生会调用回调来处理,理论上无阻塞情况减少了很多CPU的wait,这部分时间用于处理真正的业务,所以异步模型能够带来很高的CPU处理能力,减少等待,单位时间处理的事件越多,从外部来看并发就很高,实际上也是一个串行的工作状态,但是串行过程没有等待。

答案对人有帮助,有参考价值1答案没帮助,是错误的答案,答非所问
维生素CC 77 2013年04月17日 回答

对于node可以从process.nextTick()入手看

答案对人有帮助,有参考价值1答案没帮助,是错误的答案,答非所问
pubby_sk 248 2013年04月23日 回答

既然是单线程异步,那么只能对IO密集型的业务能显著提高并发,对CPU密集型业务没有太大优势。

答案对人有帮助,有参考价值1答案没帮助,是错误的答案,答非所问
blankyao 294 2013年04月23日 回答

在node.js里面只有你写的代码是单线程的,其内部并不是单线程的,只是它实现了这个机制,让用户写的代码都是单线程的。推荐篇文章给你: Node is Not Single Threaded

答案对人有帮助,有参考价值0答案没帮助,是错误的答案,答非所问
dyzdyz010 1k 2013年04月17日 回答

参考Node.js开发指南

答案对人有帮助,有参考价值0答案没帮助,是错误的答案,答非所问
GR_Art 5 2014年02月20日 回答

可以看下这往篇文章

nodejs是单线程的更多相关文章

  1. Nodejs:单线程为什么能支持高并发?

      1.Nodejs是一个平台,构建在chrome的V8上(js语言解释器),采用事件驱动.非阻塞模型( c++库:libuv). 参考官方: Node.js is a platform built ...

  2. 既然nodejs是单线程的,那么它怎么处理多请求高并发的?

    单线程解决高并发的思路就是采用非阻塞,异步编程的思想.简单概括就是当遇到非常耗时的IO操作时,采用非阻塞的方式,继续执行后面的代码,并且进入事件循环,当IO操作完成时,程序会被通知IO操作已经完成.主 ...

  3. nodejs 单线程 高并发

    nodejs为什么是单线程且支持高并发的脚本语言呢? 1.node的优点:I/O密集型处理(node的I/O请求都是异步的,如:sql查询.文件流操作.http请求……):异步I/O?顾名思义就是异步 ...

  4. [NodeJS] 优缺点及适用场景讨论

    概述: NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. ...

  5. nodejs中异常错误的处理方式

    因为nodejs是单线程的,所以一旦发生错误或异常,如果没有及时被处理整个系统就会崩溃.错误异常有两种场景的出现,一种是代码运行中throw new error没有被捕获,另一种是Promise的失败 ...

  6. 过年7天乐,学nodejs 也快乐

    自从上次接触nodejs 已经好长时间了,但是年底公司太忙了 ,没时间看, 上次文章在ubuntu上安装nodejs[开启实时web时代] http://www.cnblogs.com/qqlovin ...

  7. NodeJS中的异步I/O、事件驱动

    nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...

  8. Nodejs学习路线图

    前言 用Nodejs已经1年有余,陆陆续续写了48篇关于Nodejs的博客文章,用过的包有上百个.和所有人一样,我也从Web开发开始,然后到包管 理,再到应用系统的开发,最后开源自己的Nodejs项目 ...

  9. Nodejs学习笔记(一)——初识Nodejs

    前言:目前工作的分内之事相对较为单一,希望可以通过工作之余的时间给自己充充电,只是没有一个学伴或大神带,只能说是摸索着前进.起初准备好好研究下Spring这个框架,下载了源码,结合书籍准备一探究竟,看 ...

随机推荐

  1. Delphi数组复制

    const AA : arrary[0..4] of byte =(0,1,2,3,4) var BB : arrary[0..4] of byte; begin BB := AA ;   {这样是错 ...

  2. cordova在app内部指定浏览器打开链接插件:cordova-plugin-inappbrowser

    原文网址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-plugin-inappbrowser/ 要想App里边的 ...

  3. Markdown Test

    P1 1.1 interview 1.2 invoker show 1.3 Wtf? P2 for example this is a story int main() { printf(" ...

  4. poj 2152 树形DP

    思路:这个没思路,看了陈启峰的论文写得. #include<map> #include<set> #include<cmath> #include<queue ...

  5. 前端工作流程自动化——Grunt/Gulp 自动化

    什么是自动化 先来说说为什么要自动化.凡是要考虑到自动化时,你所做的工作必然是存在很多重复乏味的劳作,很有必要通过程序来完成这些任务.这样一来就可以解放生产力,将更多的精力和时间投入到更多有意义的事情 ...

  6. 【转载】MQTT学习笔记——MQTT协议体验 Mosquitto安装和使用

    http://blog.csdn.net/xukai871105/article/details/39252653 0 前言     MQTT是IBM开发的一个即时通讯协议.MQTT是面向M2M和物联 ...

  7. Android异步下载网络图片

    最近新做的一个项目,里面需要下载网络上的图片,并显示在UI界面上,学Android有个常识,就是Android中在主线程中没法直接更新UI的,要想更新UI必须另外开启一个线程来实现,当开启的线程完成图 ...

  8. 一个页面多Table多分页的问题

    一个页面有多个table,多个pagination,一个pagerForm.这种情况下怎么解决多个pagination不同pagenum的问题呢? 如果是这样的滴话,使用局部刷新就可以了,两个tabl ...

  9. Zend studio 12.5.1破解过程

    开始学习php了 今天又安装了一下Zend  之前找了很久的教程终于成了 , 今天换了一台电脑需要重新安装一下 又点忘记了. 就讲这个过程写下来 1.安装zend studio 12.5.1.这个过程 ...

  10. 如何用ASP.NET实现bosh模拟http双向长连接请求

    在做研究之前先简单说一下之前公司的通讯模块.最早的时候公司开发的web管理系统是需要配合c++桌面客户端进行一些系统底层操作,并非普通的b/s架构,或者c/s架构,因为需求是可以通过web管理系统向客 ...