理解Node.js的事件轮询

前言

总括

智者阅读群书。亦阅历人生

正文

Node.js的两个基本概念

Node.js的第一个基本概念就是I/O操作开销是巨大的:

所以,当前变成技术中最大的浪费来自于等待I/O操作的完毕。有几种方法能够解决性能的影响:

  • 同步方式:按次序一个一个的处理请求。:简单。:不论什么一个请求都能够堵塞其它全部请求。
  • 开启新进程:每一个请求都开启一个新进程。:简单;:大量的链接意味着大量的进程。
  • 开启新线程:每一个请求都开启一个新线程。:简单,并且跟进程比。对系统内核更加友好。由于线程比进程轻的多;:不是全部的机器都支持线程,并且对于要处理共享资源的情况,多线程编程会非常快变得太过于复杂。

第二个基本概念是每一个连接都创建一个新线程是非常消耗内存的(比如:你能够对照Nginx回忆一下Apache内存耗尽的情景)。

Apache是多线程的:它为每一个请求开启一个新的线程(或者是进程,这取决于你的配置),当并发连接增多时。你能够看看它是怎么一点一点耗尽内存的。Nginx和Node.js不是多线程的,由于线程的消耗太“重”了。

它们两个是单线程、基于事件的。这就把处理众多连接所产生的线程/进程消耗给消除了。

单线程

确实仅仅有一个线程:你不能并行运行不论什么代码。比方:以下的“sleep”将会堵塞sever1秒钟:

function sleep() {
   var now = new Data().getTime();
   while (new Date().getTime() < now + 1000) {
         // do nothing
   }
}
sleep();

但就我眼下学习阶段而言,我认为好多人对于所谓的node单线程是有误解的。实际上官方给出的“单线程”是具有误导性的。所谓的单线程是指你的代码仅仅运行在一个线程上(好多地方都叫它主线程。实际上Javascript的浏览器运行环境不也是这么处理我们写的Javascript代码的嘛),而诸多任务的并行处理,就须要多线程了,例如以下图:

如上图,Node.js中的单线程之说指的就是这个主线程。这个主线程有一个循环结构。保持着整个程序(你写的代码)的运转。

事件轮询

事实上上面我们所说的维持主线程运行的循环这部分就是”事件轮询”,它存在于主线程中,负责不停地调用开发人员编写的代码。但对开发人员是不可见的。so…开发人员编写的代码是如何被调用的呢?看下图:

如上图,异步函数在运行结束后。会在事件队列中加入一个事件(遵循先进先出原则),主线程中的代码运行完毕后(即一次循环结束),下一次循环開始就在事件队列中”读取”事件,然后调用它所相应的回调函数(所以回调函数的运行顺序是不一定的)。假设开发人员在回调函数中调用了堵塞方法(比方上文中的sleep函数),那么整个事件轮询就会堵塞,事件队列中的事件得不到及时处理。正由于这样,nodejs中的一些库方法均是异步的,也提倡用户调用异步方法。

var fs = require(‘fs‘);
fs.readFile(‘hello.txt‘, function (err, data) {  //异步读取文件
  console.log("read file end");
});
while(1)
{
    console.log("call readFile over");
}

如上代码,我们尽管使用了异步方法readfile读取文件,但read file end永远不会输出。由于代码始终在while循环中。下一次事件轮询始终没法開始,也就没法’读取’事件队列调用相应的回调函数了。

最后有一个Node-sample是博主平时积累的一些代码。包括凝视,汇总成了一个小应用,还是能够看到学习的蛛丝马迹的。感兴趣的您能够看看。

后记

參考文章:

原文地址:https://www.cnblogs.com/llguanli/p/8453648.html

时间: 2024-12-29 11:23:55

理解Node.js的事件轮询的相关文章

node.js的事件轮询机制

借助libuv库实现的 概括事件轮询机制:分为六个阶段1.timers 定时器阶段计时和执行到点的定时器回调函数 2.pending callbacks某些系统操作(例如TCP错误类型) 3.idle,prepare 4.poll轮询阶段(轮询队列)如果轮询队列不为空,依次同步取出轮询队列中第一个回调函数,直到轮询队列为空或者达到系统最大限制如果轮询队列为空 如果之前设置过setImmediate函数,直接进入下一个check阶段,如果之前没有设置过setImmediate函数,在当前 poll

理解JavaScript中的事件轮询

原文:http://my.oschina.net/u/154866/blog/211837 Event Loop是一个很重要的概念,指的是计算机系统的一种运行机制,JavaScript语言就采用的这种机制,来解决单线程运行带来的一些问题. 想要理解Event Loop,就要从程序的运行模式讲起.“进程”是指程序的一次执行,一般情况下,一个进程一次只能执行一个任务.线程是CPU的基本调度单位. 如果有多个任务需要执行,不外乎三种解决方法. 排队.因为一个进程一次只能执行一个任务,只好等前面的任务执

理解 node.js 的事件循环

node.js 的第一个基本观点是,I/O 操作是昂贵的: 目前的编程技术最大的浪费来自等待 I/O 操作的完成.有几种方法可以解决这些对性能的影响(来自Sam Rushing): 同步:依次处理单个请求. 优点:简单. 缺点:任何一个请求都会阻塞其余请求. 创建新进程:为每个请求创建一个进程处理 优点:容易. 缺点:扩展性不好,数百个连接意味着数百个进程.fork()是 Unix 程序员的锤子.因为它很有用,所有的问题都像是钉子.但这通常是多余的. 线程:为每个请求创建一个线程处理. 优点:容

【译】理解node.js事件轮询

Node.js的第一个基本论点是I/O开销很大. 当前编程技术中等待I/O完成会浪费大量的时间.有几种方法可以处理这种性能上的影响: 同步:每次处理一个请求,依次处理.优点:简单:缺点:任何一个请求都可以阻塞所有其他的请求. Fork一个新进程:开一个新进程来处理每个请求.优点:容易:缺点:不能很好的扩展,成百上千个连接意味着成百上千个进程.fork()函数相当于Unix程序员的锤子,因为它很有用,每个问题看起来就像一个钉子,通常会被过度使用.(译者注:直译比较拗口,我理解的意思是,Unix程序

node.js事件轮询(1)

事件轮询(引用) 事件轮询是node的核心内容.一个系统(或者说一个程序)中必须至少包含一个大的循环结构(我称之为"泵"),它是维持系统持续运行的前提.nodejs中一样包含这样的结构,我们叫它"事件轮询",它存在于主线程中,负责不停地调用开发者编写的代码.我们可以查看nodejs官方网站上对nodejs的说明: Node is similar in design to and influenced by systems like Ruby's Event Mach

浅析libuv源码-node事件轮询解析(1)

好久没写东西了,过了一段咸鱼生活,无意中想起了脉脉上面一句话: 始终保持自己的竞争力.所以,继续开写! 一般的JavaScript源码看的已经没啥意思了,我也不会写什么xx入门新手教程,最终决定还是啃原来的硬骨头,从外层libuv => node => v8一步步实现原有的目标吧. libuv核心还是事件轮询,前几天从头到尾看了一遍官网的文档,对此有了一些更深的理解. (虽然现在开发用的mac,但是为了衔接前面的文章,所以代码仍旧以windows系统为基础,反正差别也不大) 首先看一眼官网给的

浅析libuv源码-node事件轮询解析(4)

这篇应该能结,简图如下. 上一篇讲到了uv__work_submit方法,接着写了. void uv__work_submit(uv_loop_t* loop, struct uv__work* w, enum uv__work_kind kind, void (*work)(struct uv__work* w), void (*done)(struct uv__work* w, int status)) { // 上篇主要讲的这里 初始化线程池等 uv_once(&once, init_on

JS中的异步以及事件轮询机制

一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步均是通过多线程实现的,没有循环队列一说,直接在子线程中完成相关的操作) JavaScript的单线程,与它的用途有关.作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM.这决定了它只能是单线程,否则会带来很复杂的同步问题.比如,假定JavaScript同时有两个线程,一个

JS高阶---事件循环模式(事件轮询)

大纲: 相关知识点: 主体: (1)模型原理 JS部分:初始化代码执行 WebAPIS:执行上下文对象(不是一个真的对象,而是一个抽象的虚拟对象,可以看做栈里的一个区域,包含很多对象) setTimeout:定时器管理模块(分线程) DOM(document):事件响应管理模块(分线程)callback queue:回调函数队列---→待执行JS中的stack初始化代码优先执行,当执行完毕后,才会执行回调代码 重点: 先执行初始化代码,执行完毕后才会循环遍历“”回调队列“”里的回调代码 (2)相