zoukankan      html  css  js  c++  java
  • I/O事件

    I/O事件

    最近在研究tornado和gevent,里面涉及了非阻塞I/O。在了解非阻塞I/O之前,需要先了解I/O事件

    我们知道,内核有缓冲区。假设有两个进程A,B,进程B想读进程A写入的东西(即进程A做写操作,B做读操作)。进程A需要先写入到内核缓冲区中,然后B从内核缓冲区中读取,如图:

    进程B会监听内核缓冲区的变化

    I/O事件的阻塞与同步

    1. 当内核缓冲区为空的时候,进程B会阻塞住
    2. 当A往内核缓冲区写入时,内核缓冲区就不是空状态了,这时候就会唤醒进程B
    3. 如果缓冲区满了,但是进程B没有被唤醒,就会通知进程A,告诉A不要再写入数据了,也就是进程A被阻塞
    4. 当进程B被唤醒后,B就从缓冲区读取数据,由于B在读数据,缓冲区就不会是满的状态了,这时候就会通知A继续写数据,也就是进程A被唤醒
    5. 如果进程A还没有唤醒,而缓冲区被B读完了(缓冲区为空),这时候就会阻塞进程B

    阻塞I/O的缺点

    在阻塞I/O情况下,一个线程只能处理一个流的I/O事件。也就是说,如果想处理多个流的I/O事件,就必须使用多进程(fork),或者多线程——效率太低

    处理I/O的第二种方法

    除了使用阻塞I/O,还可以使用非阻塞I/O的方式。
    最开始能想到的就是用轮询的方法:依次询问每个流,如果缓冲区不为空,就进行操作;否则,询问下一个流
    但是这种方法效率很低,会白白浪费掉CPU资源。于是便引入了代理——poll

    poll

    poll代理可以同时观察很多I/O流事件,在空闲的时候(即没有I/O事件的时候),会阻塞当前线程;当有I/O事件的时候,会被唤醒,然后把所有流轮询一遍
    这样就能通过减少盲目的轮询来减少对CPU资源的浪费
    但是,使用这个也有缺点:由于每次唤醒都需要把所有流都轮询一遍,当流很多的时候,轮询的时间会很长

    poll进化版——epoll

    epoll是基于事件的轮询,它会记录是哪个流产生了I/O事件,然后针对这个流来进行操作,大大降低了复杂度

  • 相关阅读:
    ELK 一些截图
    AD域
    NPOI
    搭建harbor
    【【【【日常问题记录】】】】
    golang yaml配置文件解析
    golang操作mysql使用总结
    【转】mysql优化步骤
    【转】Mysql事务,并发问题,锁机制
    golang curl
  • 原文地址:https://www.cnblogs.com/eric-nirnava/p/IO.html
Copyright © 2011-2022 走看看