V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cc959798
V2EX  ›  程序员

请问 IO 多路复用到底解决了什么问题?

  •  
  •   cc959798 · 2016-04-21 10:13:25 +08:00 · 7324 次点击
    这是一个创建于 3142 天前的主题,其中的信息可能已经有所发展或是发生改变。

    IO 多路复用为什么比单线程阻塞处理速度效率高?它节约了哪些时间? IO 中什么叫做数据准备好了

    12 条回复    2016-04-21 23:13:30 +08:00
    noli
        1
    noli  
       2016-04-21 10:26:14 +08:00
    支持 IO 多路复用的系统 API (例如 `epoll` `Kqueue`,甚至 `select` 也算) 能够在一个线程中,通过一次系统调用,获取多个 异步事件的通知。

    如果没有这样的 API ,在等待一个 IO 事件并阻塞的时候,无法知道其他 IO 事件的发生,就得拼 CPU 执行速度和时间发生的频率了。
    rock_cloud
        2
    rock_cloud  
       2016-04-21 10:44:10 +08:00
    按我的理解,解决了线程切换的开销问题。
    aboutyang
        3
    aboutyang  
       2016-04-21 10:59:32 +08:00
    IO 多路复用不一定比单线程阻塞效率更高。比如就执行一个任务的情况下, IO 多路复用没有同步阻塞的效率高。

    IO 多路复用,在一个线程(这个线程是阻塞的)中监控里面注册的 socket 状态。状态改变时, socket 中已经有你需要的信息。
    aboutyang
        4
    aboutyang  
       2016-04-21 11:05:57 +08:00
    使用 IO 多路复用,如果操作系统接收到 1000 个请求,应用程序就不需要开启 1000 个线程来处理
    zzn
        5
    zzn  
       2016-04-21 11:13:15 +08:00   ❤️ 1
    物理线程虽然比进程轻量,但也没轻量到随意用,所以就有了线程池。考虑到内存限制和 CPU 调度,每个连接对应一个线程在实际应用中并不合适, IO 多路复用可以利用一个(或几个)线程专门处理 IO ,在收到完整的包后丢给线程池去处理,这样的编程模型虽然复杂一点,但能用更少的线程可以支持大量的连接。
    1. IO 多路复用为什么比单线程阻塞处理速度效率高?
    在不考虑硬件限制的情况下,不见得会效率高,没有对比过,不敢乱下结论。
    2. 它节约了哪些时间?
    最起码 CPU 调度的负载会低不少,其他看具体实现。
    3. IO 中什么叫做数据准备好了?
    就是说数据已经在内存中,可以直接读取了。但多路复用只能告诉你 IO 可读或者可写,并没有准备好数据。 IOCP 才算得上数据已经准备好了。

    只是瞎扯淡,如有错误,望指出。
    kaneg
        6
    kaneg  
       2016-04-21 13:19:16 +08:00
    在 IO 密集型的系统中, IO 多路复用可以极大的提升系统效率。尤其是对如 Python 这类多线程效率不高的语言很有用。不过 epoll , Kqueue , select 这几种好像都是与操作系统相关的,不知道哪几个是跨平台的?
    Mirana
        7
    Mirana  
       2016-04-21 13:32:39 +08:00
    在调用 io 函数的时候,主线程是 SLEEP 的
    sujin190
        8
    sujin190  
       2016-04-21 13:43:04 +08:00
    io 多路复用,其实在 cpu 层面来说效率是更低的,但性能更高,对网卡来说效率是更高的,单线程单链接来说,当然是没有 io 多路复用效率更高,但你如果有上万十万个链接的时候,线程切换,堆栈使用将会是非常大的消耗,所以这是后就是效率更高了
    pubby
        9
    pubby  
       2016-04-21 13:47:57 +08:00
    select 是跨平台的,最原始的 io 多路复用
    但是有 2 个主要限制: 1. 监控的文件描述符太少 2.效率太低,每次都要传入大量文件描述符

    epoll , kqueue , I/O Completion Ports 都解决了这些问题

    其实在 epoll 之前,还可以用 rt-signal ,用信号通知 IO 事件。
    faywong8888
        10
    faywong8888  
       2016-04-21 14:19:42 +08:00
    @kaneg 这几个都是 Linux 上支持得比较好。不怎么跨平台,但其他 os 上有类似的(比如 iocp )可以替代。
    looyao
        11
    looyao  
       2016-04-21 14:36:09 +08:00
    写 server 使用的场景偏多,比如有 10w 个连接,创建 10w 个线程显然不现实,使用 epoll/kqueue 可以把这 10w 连接交给内核来监控,有可读事件应用程序就去处理,其余时间可以做其他逻辑处理。数据准备好了就是可以收取一部分数据了,非阻塞读到 errno == EAGAIN 为止,阻塞的话可以读一次固定的 buffer size ,多次读的话可能会阻塞,所以使用 epoll/kqueue 还是推荐用非阻塞 socket 。
    SparkMan
        12
    SparkMan  
       2016-04-21 23:13:30 +08:00
    举个简单例子,百万用户链接怎么搞? java 的 Netty 采用了 Epoll ( IO 多路复用),可以接收大量用户的链接请求
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3395 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:55 · PVG 19:55 · LAX 03:55 · JFK 06:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.