当前位置: 首页 > news >正文

javascript等待异步线程完成_程序员修神之路--问世间异步为何物?

5dc4bc2af36d0a313df987f5bd844e7b.png
b88cbd60f1902e062fe6241c9eccedb8.png

异步定义

关于异步的定义,网上有很多不同的形式,但是归根结底中心思想是不变的。无论是在http请求调用的层面,还是在cpu内核态和用户态传输数据的层面,异步这个行为针对的是调用方:

一个可以无需等待被调用方的返回值就让操作继续进行的方法

在多数程序员的概念中一般是指线程处理的层面:

异步是计算机多线程的异步处理。与同步处理相对,异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程

7c89c7e52b16322248cbb666eda82349.png

可以这样通俗的理解,异步主要解决的问题是不阻塞调用方,用方这里可以是http请求的发起者,也可以是一个线程。

但此处需要明确的是:异步与多线程与并行不是同一个概念。

CPU密集型操作

我听有的同学说,异步解决的是IO密集型的操作,菜菜觉得是不准确的。异步同样可以解决CPU密集型操作,只不过场景有限而已。有一个前提:利用异步解决CPU密集型操作要求当前运行环境支持多线程才行,比如javascript这个语言,本质上它的运行环境是单线程的,所以对于CPU密集型操作,javascript会显得力不从心。

异步解决CPU密集操作一般情况下发生在同进程中,为什么这么说呢,如果发生在不同机器或者不同进程在很多情况下已经属于IO密集型的范围了。这里顺便提醒一下:IO操作可不单单是指磁盘的操作,所有有输入/输出(Input/Output)操作的都可以泛称为IO。

举个栗子吧:

在一个带有UI的软件上点击一个按钮,UI线程会发生操作行为,假如UI线程在执行过程中有一个计算比较耗时的操作(你可以想象成计算1--999999999的和),UI线程在同步操作的情况下会一直等待计算结果,在计算完毕之后才会继续执行剩余操作,在等待的这个过程中,呈现给用户的情况就是UI卡住了,俗称假死了,带给用户的体验是非常不好的。这种情况下,我们可以新启动一个线程去执行这个耗时的操作,当执行完毕,利用某种通知机制来通知原来线程,以便原来线程继续自己的操作。

启动新线程执行CPU密集型操作利用的其实就是多线程的优势,如果是单核CPU,其实这种优势并不明显

IO密集型操作

异步的优势在IO密集型操作中表现的淋漓尽致,无论是读取一个文件还是发起一个网络请求,菜菜的建议是尽量使用异步。这里首先普及一个小知识:其实每个外设设备都有自己的处理器,比如磁盘,所以每个外设设备都可以处理自己相应的请求操作。但是处理外设设备信息的速度和cpu的执行速度来比较有着天壤之别。

4847dd26b828f781932b5ba9d8d35854.png

上图展示了不同的 IO 操作所占用的 CPU 时钟周期,在计算机中,CPU 的运算速度最快,以其的运算速度为基准,时钟周期为1。其次是一级缓存、二级缓存和内存,硬盘和网络最慢,它们所花费的时钟周期和内存所花费的时钟周期差距在五位数以上,更不用提跟 CPU 和一级缓存、二级缓存的差距了。

由于速度的差距,所以几乎所有的IO操作都推荐使用异步。比如当读取磁盘一个文件的时候,同步状态下当前线程在等待读取的结果,这个线程闲置的时间几乎可以用蛋疼来形容。所以现代的几乎所有的知名第三方的操作都是异步操作,尤其以Redis,Nodejs 为代表的单线程运行环境令人刮目相看。

现在是微服务盛行的时代,UI往往一个简单的按钮操作,其实在后台程序可能调用了几个甚至更多的微服务接口(关于微服务这里不展开),如果程序是同步操作的话,那响应时间是这些服务接口响应时间的和,但是如果采用的是异步操作,调用方可以在瞬间把调用服务接口的操作发送出去,线程可以继续执行下边代码或者等待所有的服务接口返回值也可以。最差的情况下,接口的响应时间为最慢的那个服务接口响应时间,这有点类似于木桶效应。

异步的回调

通过以上介绍,我们一定要记住一个知识点:异步需要回调机制。异步操作之所以能在执行结果完成之后继续执行下面程序完全归功于回调,这也是所有异步场景的核心所在,前到js的异步回调,后到cpu内核空间copy数据到用户空间完成通知 等等异步场景,回调无处不在。说道回调大部分语言都是注册一个回调函数,比如js会把回调的方法注册到执行的队列,c#会把回调注册到IOCP。这里延伸一下,在很多系统里,很多IO网络模型其实是属于同步范畴的,比如多路复用技术,真正异步非阻塞的推荐windows下的IOCP。

现在很多现代语言都支持更优秀的回调方式,比如js和c# 现在都支持async 和await方式来进行异步操作。

据说windows下的IOCP才是真正的异步非阻塞模型,求留言区验证!

4767c2b509f3331af3841f61e8e5c554.png

异步的特点

优势

1.异步操作无须额外的线程负担,使用回调的方式进行后续处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。

2.线程数量的减少,减少了线程上下文在cpu切换的开销。

3.微服务环境(调用多个服务接口的情况下)加快了上层接口的响应时间,意味着增加了上层接口的吞吐量

劣势

1.异步操作传统的做法都是通过回调函数来实现,与同步的思维有些差异,而且难以调试

2.如果当前环境有操作顺序的要求,异步操作为了保证执行的顺序需要做额外的工作

3.由于多数情况下异步的回调过程中的执行线程并非原来的线程,所以在捕获异常,上下文传递等方面需要做特殊处理,特别是不同线程共享代码或共享数据时容易出问题。

写在最后

1.在并发量较小的情况下,阻塞式 IO和异步IO的差距可能不是那么明显,但随着并发量的增加,异步IO的优势将会越来越大,吞吐率和性能上的差距也会越来越明显。

2.在压力比较小的情况下,一般异步请求的响应时间大于同步请求的响应时间,因为异步的回调也是需要时间的

3.在大并发的情况下,采用异步调用的程序所用线程数要远远小于同步调用程序所用的线程数,cpu使用率也一样(因为避免了太多线程上下文切换的成本)

为了系统性能,不要让任何设备停下来休息

相关文章:

  • python取随机数画图_python3测试工具开发快速入门教程1turtle绘图-4选择与随机数...
  • python中如何输入多行字符_python中怎么输入多行字符串
  • python饼图显示百分比_解决echarts饼图显示百分比,和显示内容字体及大小
  • java 二维数组定义长方体_47.二维数组的定义
  • zap 自定义日志格式_Go 每日一库之 zap
  • python接管已经打开ie浏览器_Python Webdriver 重新使用已经打开的浏览器实例
  • python 单例 多线程_python 单例模式
  • echarts绘制大数量折线图导致浏览器崩溃_现代浏览器内部机制
  • filestream读取文件_ASP.NET Core WebAPI文件下载
  • python怎么循环合并数组_python数组循环合并python执行系统命令四种方法比较
  • git pull 强制覆盖本地_用git简单粗暴地完成本地、服务器同步
  • github可视化工具_深度学习训练过程可视化(附github源码)
  • grep 与条件_【125】Linux 中 ps ef|grep和ps、grep详解
  • linux搜索文件_学习+使用Linux的最佳姿势,收录近600条Linux系统命令
  • onblur事件怎么触发_JavaScript第十三章节 事件
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • Android开源项目规范总结
  • Java 最常见的 200+ 面试题:面试必备
  • Nacos系列:Nacos的Java SDK使用
  • PHP CLI应用的调试原理
  • STAR法则
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • vue-cli3搭建项目
  • 代理模式
  • 力扣(LeetCode)21
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 微信小程序实战练习(仿五洲到家微信版)
  • 小李飞刀:SQL题目刷起来!
  • 一份游戏开发学习路线
  • postgresql行列转换函数
  • #ifdef 的技巧用法
  • $(function(){})与(function($){....})(jQuery)的区别
  • (145)光线追踪距离场柔和阴影
  • (2)Java 简介
  • (3)STL算法之搜索
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (HAL库版)freeRTOS移植STMF103
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (二)fiber的基本认识
  • (二十三)Flask之高频面试点
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)mysql使用Navicat 导出和导入数据库
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .FileZilla的使用和主动模式被动模式介绍
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • @kafkalistener消费不到消息_消息队列对战之RabbitMq 大战 kafka
  • @Validated和@Valid校验参数区别
  • [AIGC] 如何建立和优化你的工作流?
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [C\C++]读入优化【技巧】
  • [C++]高精度 bign (重载运算符版本)