你不妨先思考一个问题:
在单核时代,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. linux初学 :linux 常用命令(一)

    首先,是关机/重启命令,仅在虚拟机时使用,实际工作中用不到 reboot 一般不跟参数使用,输入指令即可重启 shutdown 一般需要跟参数,例: shutdown -r 延时多少分钟重启,一般使用 ...

  2. 浅议tomcat与classloader

    关于tomcat和classloader的文章,网上多如牛毛,且互相转载,所以大多数搜到的基本上是讲到了tomcat中classloader的几个层次,对于初接触classloader,看了之后还是只 ...

  3. swift(一)

    var floatNum:Float = 10.2 //浮点型 var double:Double = 10.3333 //双精度浮点型 var isSuccess:Bool = true //fal ...

  4. nginx二级域名配置

    CentOs下nginx二级域名配置 域名配置文件 命名规则:XXX.域名信息.conf 配置文件路径:etc/nginx/conf.d/xxxx.conf 配置文件内容:server { liste ...

  5. 【转载】Android开发学习笔记:Intent的简介以及属性的详解

    http://liangruijun.blog.51cto.com/3061169/634411/ 一.Intent的介绍 Intent的中文意思是“意图,意向”,在Android中提供了Intent ...

  6. aspcms中if判断语句的运用

    1.<h3 {if:"[list:isrecommend]"="1"} style="color:red;"{end if}>& ...

  7. AspxGridView ComboBoxComlum列数据联动

    第1步: 页面放置AspxGridView控件, 设置列ComboBox1, ComboBox2列, 拟通过ComboBox1列更新联动ComboBox2列. 两个数据列均为"ComboBo ...

  8. C# 线程抛异常

    异常抛出 异常抛出要在线程代码中抛出,否则捕获不到 using System; using System.Threading; namespace testthread_keyword_lock { ...

  9. Java之循环语句练习1

    最近在猛复习Java,猛刷题目ing.这个做题目的过程其实也就像搬砖一样,一点一点把最基础的巩固好,一块一块.整整齐齐地砌才能砌好一面墙.好了,不说了,我要去搬砖了. 其实不瞒你们说,我是比较喜欢数学 ...

  10. Python Opearte MS-SQL Use Pymssql

    看到很多的开源数据库会用到MySQL,Python同样也使用,但是我已经习惯使用图形化界面,操作感极强的MS-SQL 看到Python也提供MS-SQL连接方式,需要用到PyMssql. 在Windo ...