AsynchronousIO1.为什么要使用异步I/O用户体验?JavaScript在单个线程上执行。它是一个带有UI线程的线程。如果使用同步,在JavaScript执行时渲染UI就需要停止等待,这样用户体验极差。如果网页需要请求一些资源,并以同步的方式获取,那么我们就得等js从服务端完全获取到资源后,再继续执行。在此期间,UI等待,会使得与用户的交互极差,影响用户体验。体验感。//现在请求两个资源//耗时M毫秒getData('from_db');//耗时N毫秒getData('from_remote_api');如果是同步的,则需要时间(M+N);如果是Asynchronous,耗时Max(M,N);随着应用的复杂化,场景会变成M+N+...和Max(M,N,...),这时候同步和异步的优缺点就会更加突出。另一方面,随着网站和应用的扩展,数据往往会分布在多个服务器上,分布意味着M和N的值会线性增加,这也会放大异步和同步的性能差异。总结,IO是贵的,分布式IO更贵!资源分配单线程同步IO会因为阻塞IO而阻碍更好的利用硬件资源。多线程编程的优点:可以采用多核CPU,有效提高CPU利用率缺点:编程中的死锁和状态同步让程序员非常头疼。Node的异步IONode采用的异步IO使用单线程避免多线程死锁和状态同步,使用异步让单线程远离阻塞,从而更好的利用CPU。为了弥补单线程无法利用多核CPU的问题,Node提供了子进程childProcess,将一些计算量大的任务放到子进程中进行高效运行。2、阻塞I/O和非阻塞I/OBlockingIO阻塞IO操作是指IO操作发起后,线程阻塞等待IO完成,期间不能有效利用cpu。Non-blockingIO非阻塞IO操作实际上是在IO操作发起后,通过事件轮询或者事件通知机制,不断查询IO操作是否完成,或者主线程进入睡眠等待事件通知IO结束,然后继续往下执行代码。实际上,在非阻塞IO期间,CPU无论是用于查询还是用于休眠,都没有得到有效利用。依旧是同步IO。3.node的异步I/O需要一个链接来完成整个异步IO事件循环观察者请求对象。其实node的异步IO就是用到了线程池技术。当发起异步IO时,将io操作丢入线程池执行,然后主线程继续执行其他操作。io执行完成后,通过线程间通信通知主线程,主线程执行callback。IO线程由Libuv管理的线程池控制(Linux下由libeio实现;window下由IOCP实现),本质上是多线程的。即用线程池和阻塞IO来模拟异步IO。异步IO的原理遇到IO,放入线程池中的一个IO线程,让任务在IO线程上执行,在IO线程上以阻塞IO方式执行,然后在主线程上继续执行,当遇到另一个IO任务时,将其放入线程池,然后在另一个IO线程上执行(也是阻塞IO模式),主线程继续执行。1、事件循环正式的让回调函数变得非常普遍因为事件循环。1、节点进程启动时,会创建一个类似while(1)的循环,每次执行循环的过程称为`Tick`。2、Tick进程是检查此刻是否有事件需要处理,如果有则取出相关事件和回调函数,然后执行回调函数(在主线程中执行)。3.然后进入下一个循环,继续检测是否没有更多的事件处理,则退出。当I/O线程上的任务(阻塞I/O)执行时,会产生一个事件,这就是事件循环中事件的由来。2.ObserverNode中事件的主要来源是网络请求和文件IO。这些事件对应的观察者是网络I/0观察者和文件I/0观察者。3.request对象是js调用到内核完成I/O之后。这个中间过程有一个称为请求对象的中间产品。以打开一个文件为例0.异步调用任务1.js调用核心模块2.核心模块调用C++内置模块3.内置模块在`libuv`层,由平台处理。本质上,调用了`uv_fs_open`方法。4.在调用过程中,创建一个`FSReqWrap`请求对象。【这是我们主角的request对象】5.对象创建完成后,设置好参数和回调函数,就会被推入线程池中执行。6.js线程继续执行后续任务。当前的IO操作是在线程池中执行的。不管IO线程是阻塞还是非阻塞,都不会影响主线程的执行,这样就达到了异步的目的。至此,异步IO的第一步其实就完成了,回调通知就是第二步了。4.执行回调当IO线程中的任务执行完毕后,会将执行结果放入request对象中。然后通知TOCP。TOCP检查任务是否完成。如果完成,则将I/O请求对象添加到观察者队列中,并将其视为事件。然后通过事件循环执行回调函数。注意:Windows下使用TOCP,Linux下使用epoll。四、Node的非I/O异步API1、Timertimer的实现原理与异步IO相同,只是没有使用线程池。setTimeout()每tick一次,就会迭代的从红黑树中取出timer对象,然后检查是否超时。如果超时,则形成事件并执行回调函数。2.process.nextTick()立即执行一个异步任务。我们可能已经完成了setTimeout(function(){//},0);使用上面的方法比较浪费性能,使用process.nextTick()更加轻量级。process.nextTick(function(){//})区别//原来的A();B();C();A();process.nextTick(B);C();A();setImmediate(B);//或设置超时(B,0);C();
