浅谈 异步非阻塞


阻塞

线程在执行中若是遇到(I/O 操做)如磁盘读写或网络通讯,一般要耗费较长的时间,这时操做系统会剥夺这个线程的 CPU 控制权,使其暂停执行,同时 将资源让给其余的工做线程,这种线程调度方式称为 阻塞。当 I/O 操做完毕时,操做系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续 执行。这种 I/O 模式就是一般的同步式 I/O(Synchronous I/O)或阻塞式 I/O(Blocking I/O)。



非阻塞

非阻塞是这样定义的,当线程遇到 I/O 操做时,不会以阻塞的方式等待 I/O 操做的完成或数据的返回,而只是将 I/O 请求发送给操做系统,继续 执行下一条语句。当操做系统完成 I/O 操做时,以事件的形式通知执行 I/O 操做的线程,线程会在特定时候处理这个事件。



对比阻塞与非阻塞

阻塞模式下,一个线程只能处理一项任务,要想提升吞吐量必须经过多线程。


非阻塞模式下,一个线程永远在执行计算操做,这个线程所使用的 CPU 核心利用率永远是 100%,I/O 以事件的方式通知。 网络

在阻塞模式下,多线程每每能提升系统吞吐量,由于一个线程阻塞时还有其余线程在工做,多线程可让 CPU 资源不被阻塞中的线程浪费。 多线程

而在非阻塞模式下,线程不会被 I/O 阻塞,永远在利用 CPU。多线程带来的好处仅仅是在多核 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优缺点

使用同步IO,它的优势是可使程序调试方便,可是它的缺点也是明显的,程序的执行过程当中若是入到一些耗时的IO操做,程序的执行都要等待该IO的完成,在这个等待的过程当中,程序没法充分利用CPU,致使了CPU的闲置,为了充分利用CPU,和IO并行操做,经常使用的方法有2中:


(1)多线程单进程

    多线程的设计之处就是为了在共享的程序空间中,实现并行处理任务,从而达到充分利用CPU的效果。

    多线程缺点: spa

    其1、执行时(线程切换)上下文交换的开销较大,一个线程大约须要2M的内存空间,占用资源较大。
    其2、状态同步(锁)的问题,它也使得程序的编写和调用复杂化。 操作系统

(2)单线程多进程

    为了不多线程形成的使用不便问题,有的语言选择了单线程保持调用简单化,采用启动多进程的方式来达到充分利用CPU和提高整体的并行处理能力。它的缺点在于业务逻辑复杂时(涉及多个I/O调用),由于业务逻辑不能分布到多个进程之间,事务处理时长要远远大于多线程模式。

异步I/O与轮询技术

 当进行非阻塞I/O调用时,要读到完整的数据,应用程序须要进行屡次轮询,才能确保读取数据完成,以进行下一步的操做。轮询技术的缺点在于应用程序要主动调用,会形成占用较多CPU时间片,性能较为低下。现存的轮询技术有如下这些: read、select、poll、epoll、pselect、kqueue


read是性能最低的一种,它经过重复调用来检查I/O的状态来完成完整数据读取。 线程

    select是一种改进方案,经过对文件描述符上的事件状态来进行判断。 设计

    操做系统还提供了poll、epoll等多路复用技术来提升性能。

     轮询技术知足了异步I/O确保获取完整数据的保证。可是对于应用程序而言,它仍然只能算时一种同步,由于应用程序仍然须要主动去判断I/O的状态,依旧花 费了不少CPU时间来等待。上一种方法重复调用read进行轮询直到最终成功,用户程序会占用较多CPU,性能较为低下。而实际上操做系统提供了 select方法来代替这种重复read轮询进行状态判断。select内部经过检查文件描述符上的事件状态来进行判断数据是否彻底读取。可是对于应用程 序而言它仍然只能算是一种同步,由于应用程序仍然须要主动去判断I/O的状态,依旧花费了不少CPU时间等待,select也是一种轮询。

 理想的异步I/O应该是应用程序发起异步调用,而不须要进行轮询,进而处理下一个任务,只需在I/O完成后经过信号或是回调将数据传递给应用程序便可。

暂时就整理这么多吧,感受好多看过的东西都忘记了,回头会写一篇关于epoll使用的详细例子,该例子支持2W并发是经过的。哎,今天状态很差,写的很差,本打算本身多加点什么的,结果都是参考别人的,若有错误请你们指正,谢谢。

相关文章
相关标签/搜索