• 【读书笔记】《深入浅出nodejs》第三章 异步I/O


    1. 为什么要异步I/O

      (1)用户体验上:

        并发的优势: M+N+... -> max(M,N,...)  --> 使后端能够快速的响应资源

        *并发的劣势:...

      (2)资源分配:

        单线程同步编程模型会因阻塞I/O导致硬件资源得不到更优的使用。 -> 硬件使用效率低     -----

                                                   | -----> Node:利用单线程,远离多线程死锁,状态同步等问题;利用异步I/O,让单线程远离阻塞,以更好的使用CPU。

        多线程编程模型会因为编程中的死锁、状态同步等问题让开发人员头疼。 -> 编程上的困难  -----

    2. Node的异步I/O

      (1)Node自身的执行模型 -- 事件循环(令回调函数十分普遍)

        当进程启动时,Node会创建一个类似于while(true)的循环,没执行一次循环体的过程称为一次"Tick"(“滴答”一声)。

        每个Tick中,Node会:

          A. 查看是否有事件待处理(什么是事件?) 事件的来源:文件I/O,网络请求

          B. 如果有,取出事件以及相关的回调函数

          C. 如果存在关联的回调函数,就执行他们

          D. 进入下一个循环

          E. A -> 没有事件了 -> 退出

        谁来查看是否有事件? --> 观察者(一个或多个)->文件I/O观察者,网络请求观察者

        产生事件 :文件I/O,网络请求

        观察事件 :观察者

        取出并处理事件 :事件循环

      (2)请求对象 -- 是异步I/O过程中的重要中间产物,所有的状态都保存在这个对象中,包括送入线程池等待执行以及I/O操作完毕后的回调问题。(还是没明白是什么。)

      (3)异步I/O的过程:

        A.组装好请求对象,送入I/O线程池等待执行

        B.回调通知

          回调函数的行为:取出请求对象的result属性作为参数,取出oncomplete_sym属性为方法,然后调用执行,以此达到调用JavaScript中传入的回调函数的目的。

      事件循环,观察者,请求对象,I/O线程池四者共同构成了Node异步I/O模型的基本要素。

    3. 非I/O的异步API(什么意思?)

      (1)定时器

        setTimeout() -- 单次定时执行任务

        setInterval() -- 多次定时执行任务

        两者创建的定时器会被插入到定时器观察者内部的一个红黑树种,每次Tick执行时,会从该红黑树中迭代取出定时器对象,检查是否超过定时时间,如果超过,就形成一个事件,他的回调函数将立即执行。

        存在的问题:时间是非精确

      (2)process.nextTick()

        每次调用process.nextTick()方法,只会讲回调函数放入队列中,在下一轮Tick时取出执行。相较于setTimeout(fn,0)更高效(无需调用红黑树)

      (3)setImmediate()

        功能类似于process.nextTick(),但优先级要低于前者。

        具体实现上,process.nextTick()回调函数保存在一个数组中,setImmediate()的结果保存在链表中。

        在行为上,process.nextTick()在每轮循环中会将数组中的回调函数全部执行完,而setImmediate()在每轮循环中执行链表中的一个回调函数。

    4. 事件驱动与高性能服务器

      事件驱动的实质:通过主循环加事件触发的方式运行程序。

      几种经典的服务器模型:

        A. 同步式:一次只能处理一个请求,并且其余请求都处于等待状态。

        B. 每进程/每请求:为每个请求启动一个进程,这样可以处理多个请求,但是他不具备拓展性,因为系统资源只有那么多。

        C. 每线程/每请求:为每个请求启动一个线程来处理。尽管线程比进程要轻量,但是由于每个线程都占用一定内存,当大并发请求到来时,内存将会很快用光,导致服务器变缓慢。(此方式的拓展性强于每进程/每请求,但对于大型站点而言依然不够)【Apache使用】

        【Node高性能的原因之一】:Node通过事件驱动的方式处理请求,无须为每一个请求创建额外的对应线程,可以省掉创建线程和销毁线程的开销,同时操作系统在调度任务时因为线程较少,上下文切换的代价很低。这使得服务器能够有条不紊的处理请求,即使在大量连接的情况下,也不受线程上下文切换开销的影响。

  • 相关阅读:
    UVa 541 Error Correction
    UVa 11045 My T-shirt suits me
    【模板】Ford-Fulkerson算法
    POJ 1273 Drainage Ditches
    UVa 10158 War
    UVa 658 It's not a Bug, it's a Feature!
    【模板】并查集
    【模板】Floyd-Warshall算法
    UVa 10034 Freckles
    UVa 10048 Audiophobia
  • 原文地址:https://www.cnblogs.com/libinfs/p/5916209.html
Copyright © 2020-2023  润新知