链接:http://www.runoob.com/nodejs/nodejs-callback.html

首先什么是单线程异步非阻塞?

单线程的意思整个程序从头到尾但是运用一个线程,程序是从上往下执行的。异步操作就是程序虽然是从上到下执行的,但是某个函数执行时间过长时并不会阻塞在那里等待它执行完,然后在执行下面的代码。非阻塞也就是这个意思。

为什么node是异步非阻塞的呢,得力于回调函数,还有js中的定时器也是经典的异步操作。

###4.1 Node.js异步机制 由于异步的高效性,node.js设计之初就考虑做为一个高效的web服务器,作者理所当然地使用了异步机制,并贯穿于整个node.js的编程模型中,新手在使用node.js编程时,往往会羁绊于由于其他编程语言的习惯,比如C/C++,觉得无所适从。我们可以从以下一段简单的睡眠程序代码窥视出他们的区别,下面是摘自《linux程序设计》打印10个时间的C代码:

#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
time_t the_time;
for(i = ; i <= ; i++) {
the_time = time((time_t *));
printf("The time is %ld\n", the_time);
sleep();
}
exit();
}

编译后打印结果如下:

The time is 1396492137

The time is 1396492139

The time is 1396492141

The time is 1396492143

The time is 1396492145

The time is 1396492147

The time is 1396492149

The time is 1396492151

The time is 1396492153

The time is 1396492155

从C语言的打印结果可以发现,是隔2秒打印一次,按照C程序该有的逻辑,代码逐行执行。以下Node.js代码本意如同上述C代码,使用目的隔2秒打印一次时间,共打印10条(初次从C/C++转来接触Node.js的程序员可能会写出下面的代码):

function test() {
for (var i = 0; i < 10; i++) {
console.log(new Date);
setTimeout(function(){}, 2000); //睡眠2秒,然后再进行一下次for循环打印
}
};
test();

打印结果: Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
观察结果发现都是在14:53:22同一个时间点打印的,根本就没有睡眠2秒后再执行下一轮循环打印!这是为什么?从官方的文档我们看出setTimeout是第二个参数表示逝去时间之后在执行第一个参数表示的callback函数,因此我们可以分析, 由于Node.js的异步机制,setTimeout每个for循环到此之后,都注册了一个2秒后执行的回调函数然后立即返回马上执行console.log(new Date),导致了所有打印的时间都是同一个点,因此我们修改for循环的代码如下:

for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(new Date);
}, 2000); }

执行结果如下所示: Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
神奇,仍然是同一个时间点,见鬼!冷静下来分析,时刻考虑异步,for循环里每次setTimeout注册了2秒之后执行的一个打印时间的回调函数,然后立即返回,再执行setTimeout,如此反复直到for循环结束,因为执行速度太快,导致同一个时间点注册了10个2秒后执行的回调函数,因此导致了2秒后所有回调函数的立即执行。 我们在for循环之前添加console.log("before FOR: " + new Date)和之后console.log("after FOR: " + new Date),来验证我们的推测,打印结果如下(后面省略8条相同的打印行):
before FOR: Thu Apr 03 2014 09:42:43 GMT+0800 (中国标准时间)
after FOR: Thu Apr 03 2014 09:42:43 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:42:45 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:42:45 GMT+0800 (中国标准时间)
…… (省略与上一行8条相同的打印行)
由此可以窥视出Node.js异步机制的端倪了,在for循环中的代码于其后的代码几乎在一个单位秒内完成,而定时器中的回调函数则按要求的2秒之后执行,也是同一秒内执行完毕。那么如何实现最初C语言每隔2秒打印一个系统时间的需求函数呢,我实现了如下一个wsleep函数,放在for循环中,可以达到该目的:

function wsleep(milliSecond) {
var startTime = new Date().getTime();
while(new Date().getTime() <= milliSecond + startTime) {
}
}

但是该函数有一个令他无法在项目中使用的缺陷,请问为什么?

如果没有回调函数的话,就变成阻塞式的,程序基本上是从上到下执行的。主要就是因为回调函数的影响导致的

2.阻塞与非阻塞

Node.js 回调函数

Node.js 异步编程的直接体现就是回调。

异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。

例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。


阻塞代码实例

创建一个文件 input.txt ,内容如下:

菜鸟教程官网地址:www.runoob.com

创建 main.js 文件, 代码如下:

var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());
console.log("程序执行结束!");

以上代码执行结果如下:

$ node main.js
菜鸟教程官网地址:www.runoob.com 程序执行结束!

非阻塞代码实例

创建一个文件 input.txt ,内容如下:

菜鸟教程官网地址:www.runoob.com

创建 main.js 文件, 代码如下:

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
}); console.log("程序执行结束!");

以上代码执行结果如下:

$ node main.js
程序执行结束!
菜鸟教程官网地址:www.runoob.com

以上两个实例我们了解了阻塞与非阻塞调用的不同。第一个实例在文件读取完后才执行完程序。 第二个实例我们呢不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。

因此,阻塞按是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

node 单线程异步非阻塞的更多相关文章

  1. 理解Node.js异步非阻塞I/O与传统线性阻塞IO的区别(转)

    阻塞I/O 程序执行过程中必然要进行很多I/O操作,读写文件.输入输出.请求响应等等.I/O操作时最费时的,至少相对于代码来说,在传统的编程模式中,举个例子,你要读一个文件,整个线程都暂停下来,等待文 ...

  2. 爬虫基础--IO多路复用单线程异步非阻塞

    最近一直的学习爬虫  ,进行基础的学习 性能相关 参考 https://www.cnblogs.com/wupeiqi/p/6229292.html # 目标:单线程实现并发HTTP请求 # # so ...

  3. Tornado的异步非阻塞

    阻塞和非阻塞Web框架 只有Tornado和Node.js是异步非阻塞的,其他所有的web框架都是阻塞式的. Tornado阻塞和非阻塞两种模式都支持. 阻塞式: 代表:Django.Flask.To ...

  4. nodejs的异步非阻塞IO

    简单表述一下:发启向系统IO操作请求,系统使用线程池IO操作,执行完放到事件队列里,node主线程轮询事件队列,读取结果与调用回调.所以说node并非真的单线程,还是使用了线程池的多线程. 上个图看看 ...

  5. 在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树

    nginx平台初探(100%) — Nginx开发从入门到精通 http://ten 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来 ...

  6. Python web框架 Tornado(二)异步非阻塞

    异步非阻塞 阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle) 一个请求到来未处理完成,后续一直等待 解决方案:多线程,多进程 异步非阻塞(存在IO请求): Torna ...

  7. Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型

    使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...

  8. Python异步非阻塞IO多路复用Select/Poll/Epoll使用,线程,进程,协程

    1.使用select模拟socketserver伪并发处理客户端请求,代码如下: import socket import select sk = socket.socket() sk.bind((' ...

  9. nginx学习(二)——基础概念之异步非阻塞

    上面讲了很多关于nginx的进程模型,接下来,我们来看看nginx是如何处理事件的. 有人可能要问了,nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发 ...

随机推荐

  1. Python遥感数据主成分分析

    原文:http://www.cnblogs.com/leonwen/p/5158947.html 该算法由MatLab移植而来(具体参见上一篇博文).但是最终输出结果却和MatLab不一致,经排查发现 ...

  2. golang strings常用函数

    package main import ( "fmt" "strings" ) func main() { s1 := " aBc" s2 ...

  3. Hystrix(服务熔断,服务降级)

    一.Hystrix 1.服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的”扇出”,如扇出的链路上某个微服务的调用响应式过长或者 ...

  4. Loj #2529. 「ZJOI2018」胖

    Loj #2529. 「ZJOI2018」胖 题目描述 Cedyks 是九条可怜的好朋友(可能这场比赛公开以后就不是了),也是这题的主人公. Cedyks 是一个富有的男孩子.他住在著名的 The P ...

  5. 解决python错误 UnicodeDecodeError: 'gb2312' codec can't decode byte 0x8b in position 1: illegal multibyte sequence

    报错的代码: url= 'http://kaijiang.500.com/shtml/ssq/19001.shtml' page =urllib.request.urlopen(url) conten ...

  6. linux中断子系统

    参考引用:http://www.wowotech.net/sort/irq_subsystem wowotech:一个很好的linux技术博客. 一.概述 目的 kernel管理硬件设备的方式:轮询. ...

  7. ReentrantReadWriteLock 源码分析

    ReentrantReadWriteLock  源码分析: 1:数据结构: 成员变量: private final ReentrantReadWriteLock.ReadLock readerLock ...

  8. log4j打印抛出异常时堆栈内容

    JAVA 中为快速定位,抛出异常的位置.往往需要在日志中描述. log.err("异常出错点", e); 会将出错时的堆栈信息显示出来. package com.jqyc.jase ...

  9. 【Navicat】使用navicat执行sql 查询速度很慢解决方法

    ========================== Navicat 远程连接Mysql执行普通sql速度慢问题: 场景: navicat可以连接上 远程服务器的mysql.但是在navicat执行最 ...

  10. 阿里OSS前端直传

    第一次写博客,如有错误请多多指教. 先上代码吧: ossUpload = function (file, fun, funParameter) { //第一此请求后台服务器获取认证请求 $.ajax( ...