请问 IO 多路复用到底解决了什么问题? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
cc959798
V2EX    程序员

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

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

    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     Solana     3115 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 04:46 PVG 12:46 LAX 20:46 JFK 23:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86