[转]异步机制与异步原理

前言

昨天在总结javascript异步编程的时候,提到了promise和目前比较流行的async模块,不过,在比较这两个解决方案的时候,在我个人的认知上感觉两个没有什么太大的本质区别,于是去请教了一些前辈来解答两个不同方案的优劣,在解答的过程中,涉及到了对一些异步原理的部分。

然后,感觉自己整个人的三观都被刷新了。

在了解了一些原理相关的内容之后,发现自己所理解的异步太浮于表面,这和网上看到的一些人的一些技术文章有很大的关系,关于网上发布的一些所谓的技术文章,大多都没有什么权威性,大部分都是个人在某个阶段中所理解的内容,而我对异步的理解也被大量的这类文章所影响,并且深信不疑。

为了最终去了结异步到底是怎样的一个过程,以及异步所产生的初衷,我去寻找了一些比较具有权威性质的文章,然后也请教了一些对于这方面研究比较深入的前辈。

浅谈异步

对于异步,不知道是从哪里第一次接触到的这个词语,我第一次接触到异步,是源自jquery的ajax,jquery对于ajax请求开放了两种方式,一种是同步,一种是异步,而我第一次对于异步的了解就是通过ajax的异步请求。

现在,网上大多数对于异步模式产生原因的解释大多都是这样的:因为javascript的执行环境为单线程,所以程序在执行的时候只能按照顺序执行,而其中一个程序发生太大的资源消耗,会导致后面的程序过长的等待,造成阻塞的情况。

其实,乍一看,这样的解释似乎也没有什么问题,因为在javascript的编程体验上,这样的解释是比较符合开发感受的,久而久之,很多人对于异步的理解就和我一样变成了,为了解决两个需要同时执行的任务这样的理解。

不过,其实将这个想法往深追究其实是站不住脚的,因为不管是采用了怎样的机制,javascript所运行的环境已然是单线程,这是不可改变的事实(worker模块除外),这也就导致了不管表面上是怎样的,实际内部两个任务是不可能同时执行的,在任务队列中,不管怎样都是会有一个执行顺序的。

而也正是因为这样,异步其实并不能本质上解决程序阻塞的问题。

举个例子:

function bendan (callback) {

    callback();

}

bendan(() => {

    console.log(1);

    for(var i = 0; i < 100000000; i++) {

        console.log(2);

    }

});

console.log(3);

上面这段代码是一个比较好理解的异步过程,如果按照错误的异步理解方式,那么这个程序运行的结果应该是可以将3顺利的打出,甚至应该在打印2这个比较耗费资源的过程之前就打印出3,但是,实际上的结果是,这段程序在打印2的时候就发生了阻塞,3并不能顺利的打印出来。

这就是异步和多线程最本质的区别,也就此说明了,异步本质上其实解决不来资源消耗所发生的阻塞问题。

异步原理

那么,异步到底是为了解决什么样的问题的呢?或者说他究竟是怎样的情况下被发明出来的呢?

这要从javascript的特性以及发展说起,javascript这个语言在发明的过程中,其实考虑的并不是很完善,因此有很多地方和最初设想的不太一样,比较典型的例子就是闭包,闭包的产生其实最初只是因为javascript垃圾回收机制的一个缺陷所产生的一个问题,但是却意外地变成了一个彩蛋,类似这样的有很多,只不过没有其他作用的变成了坑,而可以在其他方面有发展的则变成了彩蛋。

异步其实就是如此。

javascript有一个其他语言所不太具备的方便设计,回调,当然,其他的语言现在也可以实现回调,只不过回调的实现成本比较高,就比如java之前不支持回调,如果想要实现回调的相关效果,需要定义个interface,a去赋值,b函数接收他,这个回调函数还是个局部变量,a改了,b里的也改了,然后b里再去执行,这样很繁琐。

但是javascript不一样,javascript在设计中本身就对回调进行了支持,而在往下看,回调产生了一个很有趣的东西,那就是闭包,而闭包把自身的作用域暴露给了其它对象,什么意思呢?就是说它自身也不知道什么时候会被执行,所以产生了异步,如果这个function,用了函数局部变量,那传到外面后执行也能拿到,为什么,因为作用域出去了,就是闭包,所以promise,async是为了解决这种问题,让回调函数被执行完了,再往下执行。

也就是说,异步其实在最初只是为了使用回调所产生了一个结果。

那么为什么异步就变成了彩蛋,然后现在被打大量的使用呢?还有,异步的具体使用场景究竟是什么呢?

这要从程序运行的资源消耗说起,首先要明确一个概念,运行时间长并不代表所消耗的资源多,举个简单的例子,ajax请求,在这样的请求中会有较大的时间开销,但是这一过程中并没有太大的资源消耗,或者说对于javascript所执行的环境来说几乎没有什么资源的消耗。

所以在这样的过程中,其实主线程是空闲着的,如果不是异步的行为,那它所做的只有一件事,那就是等待,等待请求的响应,那么,其实在这样的一个过程中,完全可以把主线程在等待时候的资源开放出来进行其他的操作,这就形成了异步。

虽然这样的一种行为,和多线程看似一样,因为都是在前面的程序没有执行完的时候就开始执行了下面的程序,但是实际上却是有着本质的区别,如果不是像这种等待的操作,而是运算量比较大的那种,单线程会卡住,而这种情况只有多线程能解决,异步不能。

然后,javascript是怎样做到利用这个等待资源的呢,这和javascript的运行机制有关,它会把需要执行的放在一个执行队列中,像是这种需要等待的程序,他在会在执行了之后将他排在后面,然后执行其他的任务,指导它等待结束之后,执行它的回调。

对于这样一个过程的具体实现,要引入一个叫做帧的概念,对于同步代码是在当前帧运行的,异步代码是在下一帧运行的。

盗用一个别人的讲解图。

这样就能简单的理解这个运行过程。

总结

首先,最大的感触就是,对于网络上的一些技术文章要有判断能力,虽然说这是可以获取很多新技术的最有效的途径,但是很多技术文章也都是个人的见解,他们说出的一些不具有权威性,也不需要负任何的责任,其次,最好还是多看书,大部分可以出版的内容还是具有一些权威性的,至少要比网上的要好。

其实对于异步的理解对于业务相关影响不是特别大,但是像是这样的理解偏差可能会造成一些不可预计的坑,所以能了解本质的话还是要尽量的追溯到事情的本质。

然后,现在nodejs已经可以进行多线程的编写,感兴趣的可以去找一些worker。

最后,对于这个的理解之后,我明白了promise和async的区别,async所解决的是实现了同步的写法执行异步操作,更清晰易懂的通过编写同步代码实现异步操作,对于async的理解可以再稍微看看generator,应该会有更深的理解。

转自 wanglanye

时间: 2024-10-16 15:11:12

[转]异步机制与异步原理的相关文章

JavaScript单线程和异步机制

随着对JavaScript学习的深入和实践经验的积累,一些原理和底层的东西也开始逐渐了解.早先也看过一些关于js单线程和事件循环的文章,不过当时看的似懂非懂,只留了一个大概的印象:浏览器中的js程序时是单线程的.嗯,就这么点印象.当时也有些疑问:既然是单线程的,那异步调用是怎么实现的?计时器是靠谁来计时的,这单线程总不能一边执行程序一边计时吧?那些耗时的I/O操作为啥没把线程阻塞,不是说好的单线程么?相信很多不了解JavaScript单线程的同学也有过类似的疑问. 今天看了不少相关的资料,就详细

异步机制

Linux 内核中使用到异步机制的地方: 信号,这是一种进程间通信的异步机制 [通信] epoll,这是一种高效I/O的异步通信机制 [I/O] 信号的本质: 软中断信号(signal,又简称为信号),用来通知进程发生了异步事件.在软件层次上,信号是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程通信机制中唯一的异步通信机制.(一个进程不必通过任何操作来等待信号的到达,进程也不知道信号到底什么时候到达) 进程收到信号后,有3种处理方法: 1.

同步机制与异步机制的理解

同步机制与异步机制的理解 同步机制即在进行输入输出时,必须等待输入输出完毕后,才能进行后面的操作. 异步传输机制就不必等待完毕就可进行其它操作. 网络上有一个比较通俗的例子:请吃饭 同步就是我叫你吃饭,你听到了就立刻跟我去,若你没有反应,那我就不停的叫你,直到你回应.(同步的特点是我不能做其他任何的事情,专心等你...个人觉得女生肯定希望遇到此类的男生吧...) 异步就是我叫了你,然后我就去吃饭了,不管你听没听见.(异步的特点是不会等待正在执行的事件结束,他就可以执行其它的事件). 看了别人的帖

浅议事件异步处理底层实现原理

//主类 package cn.com.likeshow.bluetoothchat; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.LinearLayout; import android.widget.TextView; public class MainActivity extends Activity { @Override pr

JavaScript异步机制

单线程异步执行的JavaScript JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行.异步代表JavaScript代码在任务队列中的顺序并不完全等同于代码的书写顺序,比如事件绑定.Ajax.setTimeout()等任务的发生时间是“不可被预期”的. 既然JavaScript是单线程机制,那Ajax为什么是异步的?setTimeout()是怎样执行的? 在浏览器中,JavaScript引擎是单线程执行的.也就是说,在同一时间内,只能有一段代码被Ja

对Node.js的异步机制的思考

Node.js的异步机制是其最大的特色,异步可以应对高并发,具有很好的性能. 但是如果在某个方法里,涉及到数据库的多层查询,异步机制反而成为阻碍.当执行完第一层SQL后,根据所得的结果集(rows)进行结果集进行遍历时,每次遍历的结果作为where条件再执行下一层SQL时,下一层及以后的SQL并不会执行,而是在结果集(rows)遍历到最后时,才执行下一层SQL. 这时,若SQL只有两三层,其实倒还好,可以合并SQL:但是SQL层数多了之后,这种异步机制却是最大的阻碍.这时,就需要用到Node.j

[转]JavaScript异步机制详解

原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------------------------- 学习JavaScript的时候了解到JavaScript是单线程的,刚开始很疑惑,单线程怎么处理网络请求.文件读写等耗时操作呢?效率岂不是会很低?随着对这方面内容的了解和深入,知道了其中的奥秘.本篇文章就主要讲解一下JavaScript怎么处理异步问题. 一.同

tcp异步机制

前面关于socket的编程,全部是基于同步机制开发的服务器和客户端,线程会进入阻塞或者挂起状态,降低线程利用率,同时程序影响效率.因此,向tcp程序引入异步回调:在异步套接字完成网络操作后,线程没有被阻塞或者挂起,接着通过调用回调函数处理后续网络操作.而主线程继续执行,以实现并行执行的结果. 为什么要引入异步机制? 看到过一个解释.当我们打开一个程序时,鼠标不停地转但是就是不见界面跳转,这是其他耗时操作阻碍了ui线程,造成ui线程不能响应用户操作.如果引用异步机制,ui线程在发起耗时操作之后马上

arm驱动linux异步通知与异步IO【转】

转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO>涉及内核驱动函数二个,内核结构体一个,分析了内核驱动函数二个:可参考的相关应用程序模板或内核驱动模板二个,可参考的相关应用程序模板或内核驱动三个 描述:设备文件IO访问:阻塞与非阻塞io访问,poll函数提供较好的解决设备访问的机制,但是如果有了异步通知整套机制就更加完整了 一.阻塞 I/O,非阻塞IO,异步