热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

NodeJs异步非阻塞

一般来说,高并发的解决方案就是提供多线程模型,服务器为每个客户端请求分配一个线程,使用同步IO,系统通过线程切换来弥补同步IO调用的时间开销。比如Apache就是这种策略,由于IO

一般来说,高并发的解决方案就是提供多线程模型,服务器为每个客户端请求分配一个线程,使用同步 I/O,系统通过线程切换来弥补同步 I/O
调用的时间开销。比如 Apache 就是这种策略,由于 I/O
一般都是耗时操作,因此这种策略很难实现高性能,但非常简单,可以实现复杂的交互逻辑。

而事实上,大多数网站的服务器端都不会做太多的计算,它们接收到请求以后,把请求交给其它服务来处理(比如读取数据库),然后等着结果返回,最后再把结果发给客户端。因此,Node.js
针对这一事实采用了单线程模型来处理,它不会为每个接入请求分配一个线程,而是用一个主线程处理所有的请求,然后对 I/O
操作进行异步处理,避开了创建、销毁线程以及在线程间切换所需的开销和复杂性。

那么在了解NodeJs异步非阻塞机制之前,你是否了解同步异步,阻塞和非阻塞?

同步与非同步:更面向非IO代码
阻塞与非阻塞:更面向IO代码

什么是同步机制?

《NodeJs 异步非阻塞》
同步就是必须等待上一个函数执行完毕,才能继续向下执行

什么是异步机制?

《NodeJs 异步非阻塞》
主线程执行到类IO操作时,会调用底层封装的libuv分配线程执行,并放入队列中等待主线程循环事件抽取,详细的后面会讲到

什么是阻塞机制?

《NodeJs 异步非阻塞》
顾名思义,必须等待前一个得到结果后才能继续执行,和同步容易混淆,但阻塞主要针对的是IO操作

什么是非阻塞机制?

《NodeJs 异步非阻塞》

非阻塞,意味着不用等待前一个IO操作返回就可以直接执行其他的IO操作

想必大家已经对这些概念有了一定了解,就让我们继续向下阅读

众所周知,Javascript是单线程执行的,也就是说所有的非IO请求代码都会在主线程中同步执行,但是当我们发起IO请求时,该IO请求就不是在主线程中执行了,不然主线程就会被阻塞调,无法响应其他事件,看下图


《NodeJs 异步非阻塞》

NodeJs是异步IO调用,根据上图我们所得,当我们发起IO请求时,调用的是各个不同平台的操作系统内部实现的线程池内的线程,这里的IO请求不仅仅是读写文件,在unix中,将计算机抽象了一层,磁盘文件,硬件,套接字等几乎所有计算机资源都被抽象为文件,即IO请求就是抽象后的文件

NodeJs基于libuv的架构示意图:
《NodeJs 异步非阻塞》
什么是libuv?

Libuv是一个高性能的,事件驱动的异步I/O库,它本身是由C语言编写的,具有很高的可移植性。libuv封装了不同平台底层对于异步IO模型的实现,所以它还本身具备着Windows, Linux都可使用的跨平台能力。
https://juejin.im/post/5d412865e51d4561e84fcba7

什么是IOCP?

是windows支持多个同时发生的异步I/O操作的应用程序编程接口

根据上图所得,Node是基于libuv封装层运行来实现跨平台兼容的,所有平台兼容性的判断都由这一层来完成,并保证Node程序与unix和IOCP之间各自独立,Node在编译期间会判断平台条件,选择性编译unix目录或windows目录下的原文件到目录程序中。

具体异步IO实现图:
《NodeJs 异步非阻塞》

仔细查看上图我们发现:
构成NodeJs异步IO模型主要分四大要素

  • 事件循环
  • 观察者
  • 请求对象
  • IO线程池
           
    主线程操作
    发起异步IO调用,将请求参数(param, path, callback)等信息封装到请求对象上,然后将请求对象放入请求队列中,等待线程池给该请求分配可用线程
           
    线程池操作:
    如果线程池中有可用的线程,则取出请求队列内请求对象并分配线程,在分配的线程内执行对象中的IO操作,执行完成后将执行结果封装到请求对象中,通知线程池IO操作已经完成,然后将该线程还给线程池
           
    事件循环操作:
    底层使用了while(true)机制获取已完成IO操作的事件,并触发该事件,相对应的IO事件观察者会获取该请求对象(此时该请求对象已经涵盖了callback, param等),IO观察者取出callback和IO执行结果并调用执行函数callback

总结

Node.js 在主线程里维护了一个事件队列,当接到请求后,就将该请求作为一个事件放入这个队列中,然后继续接收其他请求。当主线程空闲时(没有请求接入时),就开始循环事件队列,检查队列中是否有要处理的事件,这时要分两种情况:如果是非 I/O 任务,就通过主线程处理,并通过回调函数返回到上层调用;如果是 I/O 任务,就从 线程池 中拿出一个线程来处理这个事件,并通过观察者指定回调函数,然后继续循环队列中的其他事件。
当线程中的 I/O 任务完成以后,通过观察者执行指定的回调函数,并把这个完成的事件放到事件队列的尾部,等待事件循环,当主线程再次循环到该事件时,就直接处理并返回给上层调用

参考文章:
https://juejin.im/post/5d412865e51d4561e84fcba7
https://www.cnblogs.com/onepixel/p/7143769.html
https://juejin.im/post/5d21f7e9e51d455071250b81
https://juejin.im/post/5af1413ef265da0b851cce80


推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 【重识云原生】第四章云网络4.8.3.2节——Open vSwitch工作原理详解
    2OpenvSwitch架构2.1OVS整体架构ovs-vswitchd:守护程序,实现交换功能,和Linux内核兼容模块一起,实现基于流的交换flow-basedswitchin ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 安装oracle软件1创建用户组、用户和目录bjdb节点下:[rootnode1]#groupadd-g200oinstall[rootnode1]#groupad ... [详细]
author-avatar
手机用户2502881923
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有