IO 多路复用为什么比单线程阻塞处理速度效率高?它节约了哪些时间? IO 中什么叫做数据准备好了
1
noli 2016-04-21 10:26:14 +08:00
支持 IO 多路复用的系统 API (例如 `epoll` `Kqueue`,甚至 `select` 也算) 能够在一个线程中,通过一次系统调用,获取多个 异步事件的通知。
如果没有这样的 API ,在等待一个 IO 事件并阻塞的时候,无法知道其他 IO 事件的发生,就得拼 CPU 执行速度和时间发生的频率了。 |
2
rock_cloud 2016-04-21 10:44:10 +08:00
按我的理解,解决了线程切换的开销问题。
|
3
aboutyang 2016-04-21 10:59:32 +08:00
IO 多路复用不一定比单线程阻塞效率更高。比如就执行一个任务的情况下, IO 多路复用没有同步阻塞的效率高。
IO 多路复用,在一个线程(这个线程是阻塞的)中监控里面注册的 socket 状态。状态改变时, socket 中已经有你需要的信息。 |
4
aboutyang 2016-04-21 11:05:57 +08:00
使用 IO 多路复用,如果操作系统接收到 1000 个请求,应用程序就不需要开启 1000 个线程来处理
|
5
zzn 2016-04-21 11:13:15 +08:00 1
物理线程虽然比进程轻量,但也没轻量到随意用,所以就有了线程池。考虑到内存限制和 CPU 调度,每个连接对应一个线程在实际应用中并不合适, IO 多路复用可以利用一个(或几个)线程专门处理 IO ,在收到完整的包后丢给线程池去处理,这样的编程模型虽然复杂一点,但能用更少的线程可以支持大量的连接。
1. IO 多路复用为什么比单线程阻塞处理速度效率高? 在不考虑硬件限制的情况下,不见得会效率高,没有对比过,不敢乱下结论。 2. 它节约了哪些时间? 最起码 CPU 调度的负载会低不少,其他看具体实现。 3. IO 中什么叫做数据准备好了? 就是说数据已经在内存中,可以直接读取了。但多路复用只能告诉你 IO 可读或者可写,并没有准备好数据。 IOCP 才算得上数据已经准备好了。 只是瞎扯淡,如有错误,望指出。 |
6
kaneg 2016-04-21 13:19:16 +08:00
在 IO 密集型的系统中, IO 多路复用可以极大的提升系统效率。尤其是对如 Python 这类多线程效率不高的语言很有用。不过 epoll , Kqueue , select 这几种好像都是与操作系统相关的,不知道哪几个是跨平台的?
|
7
Mirana 2016-04-21 13:32:39 +08:00
在调用 io 函数的时候,主线程是 SLEEP 的
|
8
sujin190 2016-04-21 13:43:04 +08:00
io 多路复用,其实在 cpu 层面来说效率是更低的,但性能更高,对网卡来说效率是更高的,单线程单链接来说,当然是没有 io 多路复用效率更高,但你如果有上万十万个链接的时候,线程切换,堆栈使用将会是非常大的消耗,所以这是后就是效率更高了
|
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 事件。 |
10
faywong8888 2016-04-21 14:19:42 +08:00
@kaneg 这几个都是 Linux 上支持得比较好。不怎么跨平台,但其他 os 上有类似的(比如 iocp )可以替代。
|
11
looyao 2016-04-21 14:36:09 +08:00
写 server 使用的场景偏多,比如有 10w 个连接,创建 10w 个线程显然不现实,使用 epoll/kqueue 可以把这 10w 连接交给内核来监控,有可读事件应用程序就去处理,其余时间可以做其他逻辑处理。数据准备好了就是可以收取一部分数据了,非阻塞读到 errno == EAGAIN 为止,阻塞的话可以读一次固定的 buffer size ,多次读的话可能会阻塞,所以使用 epoll/kqueue 还是推荐用非阻塞 socket 。
|
12
SparkMan 2016-04-21 23:13:30 +08:00
举个简单例子,百万用户链接怎么搞? java 的 Netty 采用了 Epoll ( IO 多路复用),可以接收大量用户的链接请求
|