- Node.js 12实战
- 赵荣娇
- 1365字
- 2025-02-25 04:05:54
2.7 并行和并发
1.什么是并发
并发(Concurrency)指应用能够交替执行不同的任务,类似于多线程,多线程并非是同时执行多个任务,而是以几乎不可察觉的速度在多个任务之间不断切换,以达到一种“同时执行”的效果,而事实上并不是同时执行,只是切换速度快到无法察觉。
2.什么是并行
并行(Parallellism)指应用能够同时执行不同的任务,不同的任务是可以同时执行的。
并发与并行两者很重要的区别是:并发是交替执行的,而并行是同时执行的。通俗地理解,并发是不同的代码块交替执行,并行是不同的代码块同时执行。如果某个系统支持两个或者多个动作(Action)同时存在,那么这个系统就是一个并发系统。如果某个系统支持两个或者多个动作同时执行,那么这个系统就是一个并行系统。
并行是指两个或者多个事件在同一时刻发生。而并发是指两个或多个事件在同一时间间隔发生。并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。并行是在一台处理器上“同时”处理多个任务,而并发是在多台处理器上同时处理多个任务。所以并发编程的目标是充分地利用处理器的每一个核,以达到最高的处理性能。并发强调的是一起出发,并行强调的是一起执行。并发的反义是顺序,并行的反义是串行。并发并行并不是互斥概念,只不过并发强调任务的抽象调度,并行强调任务的实际执行。
单线程解决高并发问题的方法就是采用非阻塞、异步编程的思想。当遇到非常耗时的IO操作时,采用非阻塞的方式继续执行后面的代码,并且进入事件循环,当IO操作完成时,程序会被通知IO操作已经完成。这个主要运用JavaScript的回调函数来实现。
多线程虽然也能解决高并发,但是以建立多个线程来实现,其缺点是当遇到耗时的IO操作时,当前线程会被阻塞,并且把CPU的控制权交给其他线程,这样带来的问题就是要非常频繁地进行线程的上下文切换。
并发系统与并行系统这两个定义之间的关键差异在于“存在”这个词。
Node.js是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。Node.js是单线程且支持高并发的脚本语言,IO密集型处理是Node.js的强项,因为Node.js的IO请求都是异步的。对于异步,发出操作指令,然后就可以去做别的事情了(主线程无须等待),所有操作完成后执行回调。
【示例2-7】
let a = 1; // step1:定义变量 // step2:发出指令,然后把回调函数加入事件队列(回调函数并没有执行) setTimeout(() => { console.log(a); }, 0) a = 2; // step3:赋值,回调函数没有执行 // step4:发出指令,然后把回调函数加入异步队列(回调函数并没有执行) setTimeout(() => { console.log(a); }, 0) a = 3; // step5:赋值,回调函数没有执行 // 当所有代码执行完毕,cpu空闲下来了,就会开始遍历执行事件队列里面的回调函数 // 最后输出:3 3
异步I/O的Node.js为什么可以支持高并发?因为IO操作由Node.js的工作线程执行,Node.js底层的libuv是通过多线程的线程池来并行IO操作的,主线程不需要等待结果返回,发出指令后就去执行其他事务。
3.如何处理高并发和非阻塞请求
针对每个并发请求,服务端给请求注册一个激发事件(I/O),并给一个回调函数(这个过程没有阻塞新的连接请求)。按顺序执行事件处理(I/O),处理完成后执行回调函数,接着执行下一个事件处理(I/O)。事件处理(I/O)的原理是什么呢?事件处理(异步I/O处理)是由Node工作线程去执行的(Node.js底层的libuv是通过多线程的线程池来并行I/O操作的),且主线程不需要等待返回,只要发出指令后就可以执行其他事件,所有操作完成后执行回调。