🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
现实比理想要骨感一些,但是要达成异步I/O的目标,并非难事。前面我们将场景限定在了单线程的状况下,多线程的方式会是另一番风景。通过让部分线程进行阻塞I/O或者非阻塞I/O加轮询技术来完成数据获取,让一个线程进行计算处理,通过线程之间的通信将I/O得到的数据进行传递,这就轻松实现了异步I/O(尽管这是模拟的),示意图如下: ![](https://box.kancloud.cn/2016-08-28_57c1cec26d531.png) glibc的AIO便是典型的线程池模拟异步I/O。然而遗憾的是,它存在一些难以忍受的缺陷和bug,不推荐采用。libev的作者 Marc Alexander Lehmann 重新实现了一个异步I/O的库:libeio。libeio实质上依然是采用线程池与阻塞I/O模拟异步I/O。最初,Node在 `*nix`平台上采用了libeio配合libev实现I/O部分,实现了异步I/O。在Node v0.9.3中,自行实现了线程池来完成异步I/O。 另一种我迟迟没有透露的异步I/O方案则是Windows下的IOCP,它在某种程度上提供了理想的异步I/O:调用异步方法,等待I/O完成之后的通知,执行回调,用户无须考虑轮询。但是它的内部其实仍然是线程池原理,不同之处在于这些线程池由系统内核接手管理。 IOCP的异步I/O模型与Node的异步调用模型十分近似。在Windows平台下采用了IOCP实现异步I/O。 由于Windows平台和`*nix`平台的差异,Node提供了libuv作为抽象封装层,使得所有平台兼容性的判断都由这一层来完成,并保证上层的Node与下层的自定义线程池及IOCP之间各自独立。Node在编译期间会判断平台条件,选择性编译unix目录或是win目录下的源文件到目标程序中,架构如下图: ![](https://box.kancloud.cn/2016-08-28_57c1cec281e38.png) 需要强调的一点是,这里的I/O不仅仅只限于磁盘文件的读写。`*nix`将计算机抽象了一番,磁盘文件、硬件、套接字等几乎所有计算机资源都被抽象为了文件,因此这里描述的阻塞和非阻塞的情况同样能适合于套接字等。 另一个需要强调的地方在于,我们时常提到的Node是单线程的,这里的单线程仅仅只是JavaScript执行在单线程中罢了。在Node中,无论是 `*nix`还是Windows平台,内部完成I/O任务的另有线程池。