你不妨先思考一个问题:
在单核时代,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. 怒刷DP之 HDU 1024

    Max Sum Plus Plus Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

  2. 转: ios app架构设计

    http://keeganlee.me/post/architecture/20160107 看完这一系列文章后就知道怎么回答这类问题了: App架构设计经验谈:接口的设计 App架构设计经验谈:技术 ...

  3. EasyPusher推流服务接口的.NET导出

    本文是在使用由 EasyDarwin 团队开发的EasyPusher时导出的C++接口的.NET实现 public class EasyPushSDK { public EasyPushSDK() { ...

  4. 了解ASP.NET MVC几种ActionResult的本质:HttpStatusCodeResult & RedirectResult/RedirectToRouteResult

    在本系列的最后一篇,我们来讨论最后三个ActionResult:HttpStatusCodeResult.RedirectResult和RedirectToRouteResult .第一个用于实现针对 ...

  5. Part 15 Scalar user defined functions in sql server

    Scalar user defined functions in sql server Inline table valued functions in sql server Multi statem ...

  6. java中初始化时机和顺序呢

    class Pupil{ Pupil(int age){ System.out.println("Pupil:"+age); } } class Teacher{ Pupil p1 ...

  7. iOS 数据模型 的 一般设计

  8. 8个超炫酷的纯CSS3动画及源码分享

    在现代网页中,我们已经越来越习惯使用大量的CSS3元素,而现在的浏览器也基本都支持CSS3,所以很多时候我们不妨思考一下是否可以用纯CSS3制作一些有趣或者实用的网页.本文要分享8个超炫酷的纯CSS3 ...

  9. Java获取操作系统信息

    今天在看jdk的demo时候发现java获取系统操作系统的一些信息,例如内存使用情况,于是自己也想研究研究! 百度一番,发现有2种方法! 1.sun自带的API 2.第三方jar(Sigar)   先 ...

  10. [视频]MAC中如何单独放大文本字体

    我们知道使用MAC触控板的双指合拢手势可以进行放大或缩小操作,但其对应的是整个界面内容的放大及缩小,如果仅对其文本内容进行放大或缩小,可使用快捷键进行操作. 默认的 ”Command” + “=“   ...