V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
cc959798
V2EX  ›  问与答

IO 多路复用快的原因具体是什么

  •  
  •   cc959798 · Nov 25, 2018 · 4033 views
    This topic created in 2721 days ago, the information mentioned may be changed or developed.

    比如 epoll,能管理大量的连接 1.但是有个疑问是,这些连接的处理也是处理器来操作的,也是要耗费大量时间的,为什么使用 epoll 来管理就快了呢,一个个处理不是也是一样的吗? 2.文件描述符 fd 的数据准备好 具体是指什么?磁盘?网络? 3.另外 IO 多路复用是数据的准备操作是在一个线程里处理的吗?还是说 fd 被丢给了其他线程,然后主线程等着数据准备

    14 replies    2018-11-26 17:59:38 +08:00
    ech0x
        1
    ech0x  
       Nov 25, 2018 via iPhone
    没有创建进程 /线程开销
    gamexg
        2
    gamexg  
       Nov 25, 2018   ❤️ 2
    特点不是快,而是可以节省系统资源。

    最基础的同步阻塞模式意味着随着连接数增加需要增加系统线程,而系统线程成本比较高。

    非阻塞模式等于不管有没有数据不断遍历所有 socket,这会浪费 cpu。

    epoll 则是非阻塞的优化版本,不用自己去挨个尝试去读取所有 socket 看看哪个可用,系统在 socket 可用时通知应用层。
    lhx2008
        3
    lhx2008  
       Nov 25, 2018 via Android
    1.原来 IO 没返回要开线程等着,现在线程可以复用了
    2.应该是系统的 IO 缓冲区中,对方已经传了一些数据到内存了(不确定,看看楼下大神怎么说),线程可以来拿了
    3.应该在系统内核中的线程管理 ,具体原理我也不太清楚
    kran
        4
    kran  
       Nov 26, 2018 via Android
    不恰当类比一下,吞吐能力上去了,但单个响应不一定快的。
    secondwtq
        5
    secondwtq  
       Nov 26, 2018
    个人意见:不知道楼主上没上过体系结构的课,我们有一部分是讲 IO 的,当然是硬件层面,先讲了 busy wait 模式,然后说这样会阻塞 CPU 不实用,然后讲了 interrupt 和 DMA 模式,这个是现代 CPU 一直在用的

    而在学写 server 时(同样处理 IO 问题),会先学写单线程单请求的,然后是多线程每个线程一个请求的,然后是多路复用的

    有没有发现区别 ... 硬件上处理 IO 根本就没有线程的概念,因为主流体系架构使用的 IO 控制机制压根就跟线程没关系(当然 interrupt handler 执行之前会触发 context switch,不过线程建立在此基础之上),用线程来处理 IO 问题的抽象是不合适且不必要的

    你可以粗暴的认多路复用是系统提供给用户操作更底层 IO 处理机制的最低成本的一种抽象
    cc959798
        6
    cc959798  
    OP
       Nov 26, 2018
    @gamexg 你好,我可能没表达清楚,其实你说的这些我还是都明白的,可能不明白的是 文件描述符的数据准备这个概念,这个什么叫做数据准备,读磁盘,还是什么,另外如果所有的文件描述符在一个线程里处理,文件准备这个操作也是在同一个线程里处理的,这样连接多了不会也会造成处理的很多连接处理的很慢吗,仅仅是为了省资源?
    cc959798
        7
    cc959798  
    OP
       Nov 26, 2018
    @lhx2008 🤦‍♀️
    gamexg
        8
    gamexg  
       Nov 26, 2018
    @cc959798 #6

    https://segmentfault.com/a/1190000008836467

    “ sk_data_ready: 通知 socket 数据包已经准备好”
    cyspy
        9
    cyspy  
       Nov 26, 2018
    @cc959798 同步阻塞模式下高并发的时候就不只是慢的问题了, 比如 64bit Java 默认一个线程要 1M 内存,小机器很容易就吃满了
    cc959798
        10
    cc959798  
    OP
       Nov 26, 2018
    @gamexg 你的意思是说,网卡或者说硬件设备数据到达内存或者处理的进程是比较慢的,相比建立连接来说,为了节约这部分时间,我们仅仅 handle 连接,不做处理,仅仅等待他数据到达了我们在处理,也就是说 io 多路复用节约的是这部分时间,对请求的处理该是多少就是多少?
    gamexg
        11
    gamexg  
       Nov 26, 2018
    @cc959798 #10
    io 多路复用不节省时间,不增加速度。

    x 年前单机 10k 连接挑战时,如 @cyspy #9 所说,"比如 64bit Java 默认一个线程要 1M 内存,小机器很容易就吃满了",10k 个连接如果开 10k 个线程,光线程本身就会占用 1M*10k = 10G 内存,非常浪费了。

    io 多路复用,复用的是线程。可以理解为使用同步阻塞模式,每个连接 read 都需要一个线程。而使用 io 多路复用意味着一个线程可以处理多个 socket 的 read。这里的意图是节省线程这个成本较高的资源。

    然后注意 上个连接中 “调用完 sk_data_ready 之后,一个数据包处理完成,等待应用层程序来读取,上面所有函数的执行过程都在软中断的上下文中。”,也就是在 socket read 准备好之前的所有操作都是内核 ksoftirqd 进程负责的,并不需要用户进程的线程处理。既然之前的操作不需要用户线程,那么为什么要一个连接浪费一个线程等待 read 返回?所以慢慢发展出来了 epoll,一个线程可以等待一批 socket,反正在准备好之前都是内核 ksoftirqd 进程处理,用户线程一直在等待数据准备好,相当于等待一个锁。
    cc959798
        12
    cc959798  
    OP
       Nov 26, 2018
    @gamexg 嗯嗯,谢谢,也就说分两个方面理解,不是加速而是能不能到问题,或者说节省了资源,加快了吞吐让人感觉是变快了,io 多路复用和阻塞着连接是一样的,只不过一个线程处理多个。
    另外一个方面是读取网络来的请求时耗时的(不管具体怎样),我们没必要等着,发现有数据准备好的我们就开始读取数据

    我一开始可能理解的有些问题,网上的资料都是着重于将 epoll 的原理,其他的不太详细,所以才有疑问😳

    一开始想到的是,我们读取请求之后,处理请求都是一样的,无论你 io 多路复用还是阻塞着来,所以感觉总是时间是一样的,忽视了请求到来和读取完毕这个过程中还是有很多工作要做的,所以才疑惑,不过多谢啦
    julyclyde
        13
    julyclyde  
       Nov 26, 2018
    所谓快是相当于多进程多线程来说的
    节省了 CPU 切换进程时的开销
    chashao
        14
    chashao  
       Nov 26, 2018
    我以为 IO 复用是 IO 的速度相对于太慢- -然后让 CPU 等待 IO 完成不值得,这样只能用多线程,但是多线程占用内存多,不过多线程可以让系统来调度,IO 复用就需要自己来维持连接状态- -不知道这样对不对
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5436 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 07:09 · PVG 15:09 · LAX 00:09 · JFK 03:09
    ♥ Do have faith in what you're doing.