学习nodejs时,看到它的简介说它是采用异步I/O与事件驱动的架构设计,搜了很多关于同步I/O和异步I/O的资料感觉也没咋看明白,直到看了nodejs开发指南这本书第3.2节才对异步式I/O有了清晰地认识。
阻塞I/O(同步I/O)
线程在执行中如果遇到磁盘读写或网络通信(统称为 I/O 操作), 通常要耗费较长的时间,这时操作系统会剥夺这个线程的 CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。当 I/O 操作完毕时,操作系统 将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行。这种 I/O 模式就是通常的阻塞式 I/O(同步I/O) 。
非阻塞I/O(异步I/O)
非阻塞式 I/O(异步I/O) 则针对所有 I/O 操作不采用阻塞的策略。当线程遇到 I/O 操作时,不会以阻塞的方式等待 I/O 操作 的完成或数据的返回,而只是将 I/O 请求发送给操作系统,继续执行下一条语句。当操系统完成 I/O 操作时,以事件的形式通知执行 I/O 操作的线程,线程会在特定时候处理这个 事件。为了处理异步 I/O,线程必须有事件循环,不断地检查有没有未处理的事件,依次予以处理。
多线程同步I/O
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程,一个线程阻塞时还有其他线程在工作,多线程可以让 CPU 资源不被阻塞中的线程浪费。
单线程异步I/O
单线程异步I/O维护一个事件队列,程序在执行时进入事件循环等待下一个事件到来,每个异步式 I/O 请求完成后会被推送到事件队列,等待程序进程进行处理。在这个模式下,一个线程永远在执行计算操作,这个线程所使用的 CPU 核心利用率永远是 100%。
nodejs采用单线程异步I/O的优势与弊端
优势
从多线程同步I/O与单线程异步I/O的两个示例图来看,它们完成N个事件的时间理论上是一样的,不同的是,异步式 I/O 少了多线程的开销,对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU 的缓存被清空,切换回来的时候还要重新从内存中读取信息,而单线程异步I/O可以有效避免这种频繁的上下文切换。
弊端
异步式编程的缺点在于不符合人们一般的程序设计思维,容易让控制流变得晦涩难懂,给编码和调试都带来不小的困难。