CodeWalk

asyncio的epoll/kqueue/selectors底层的跨平台实现

作者:编译有声 · 2026-05-30 12:55

请深入对比asyncio在Linux(epoll)、macOS/BSD(kqueue)和Windows(IOCP/select)上的底层I/O多路复用实现差异。为什么Windows上asyncio性能较差?ProactorEventLoop和SelectorEventLoop的区别是什么?

回答

编译有声

I/O多路复用对比

1. Linux — epoll(默认)

  • 特点:O(1)事件通知,无需轮询所有fd
  • 触发模式:边缘触发(ET)或水平触发(LT),asyncio使用LT
  • 性能:大规模连接(>1000)时远优于select/poll
  • 实现:Python 3.4+默认使用EpollSelector
  • 限制:仅Linux可用

2. macOS/BSD — kqueue

  • 特点:类似epoll的功能,支持更多事件类型(文件变更、信号等)
  • 性能:与epoll相近

3. Windows — select(SelectorEventLoop默认)

  • select限制:最大监视文件描述符数为1024,轮询所有fd
  • 性能:大规模并发连接时性能急剧下降

4. Windows — IOCP(ProactorEventLoop)

  • IOCP:Windows原生异步I/O模型,真正的完成端口
  • 需先使用asyncio.set_event_loop_policy(WindowsProactorEventLoopPolicy())
  • 优势:支持真正的异步I/O,不阻塞线程

SelectorEventLoop vs ProactorEventLoop

特性SelectorEventLoopProactorEventLoop
模型Reactor(就绪通知)Proactor(完成通知)
I/O方式主动轮询就绪状态回调通知I/O完成
平台类UnixWindows
性能epoll/kqueue高效IOCP高效
subprocess支持有限支持

跨平台一致性

import asyncio
import sys

async def main():
    reader, writer = await asyncio.open_connection('example.com', 80)
    writer.write(b'GET / HTTP/1.0\r\n\r\n')
    data = await reader.read()
    print(data.decode())
    writer.close()

if sys.platform == 'win32':
    asyncio.set_event_loop_policy(
        asyncio.WindowsProactorEventLoopPolicy()
    )

asyncio.run(main())

性能建议: Linux/macOS用默认事件循环;Windows生产环境用ProactorEventLoop