Python中asyncio内部如何基于select实现?

基于 select+socket+asynico 的基础实现.

将 asyncio.get_event_loop() 换成自己写的 selfayncio.get_event_loop(), 然后其他调用方法完全一样

每秒能处理 5000 个 index html 请求. ab 并发 2w 没压力, 好像最高只能写-c 20000?


<script src=“

https://gist.github.com/Petelin/bf2eb99748ce62de0307a0df82077d77 <button onclick="lazyGist(this)"> 显示 Gist 代码 </button>
.js”></script>
Python中asyncio内部如何基于select实现?


4 回复

root@env-pay:~# siege -b -c 200 http://127.0.0.1:8080/
** SIEGE 3.0.8
** Preparing 200 concurrent users for battle.
The server is now under siege…^C
Lifting the server siege… done.

Transactions: 422665 hits
Availability: 100.00 %
Elapsed time: 73.83 secs
Data transferred: 12.50 MB
Response time: 0.03 secs
Transaction rate: 5724.84 trans/sec
Throughput: 0.17 MB/sec
Concurrency: 199.12
Successful transactions: 422665
Failed transactions: 0
Longest transaction: 3.22
Shortest transaction: 0.00


Python的asyncio在底层确实基于select(更准确地说是selectors模块),但实现机制比直接使用select要复杂得多。核心在于事件循环(Event Loop)和协程调度器。

简单来说,asyncio的事件循环会:

  1. 维护一个任务队列(ready队列)
  2. 使用selector监控所有注册的socket文件描述符
  3. 当某个socket可读/可写时,唤醒对应的协程继续执行

看个最简化的实现原理:

import selectors
import socket
from collections import deque

class SimpleEventLoop:
    def __init__(self):
        self.selector = selectors.DefaultSelector()
        self.ready = deque()  # 就绪任务队列
        self.scheduled = []   # 定时任务
        
    def add_reader(self, fd, callback):
        """注册读事件回调"""
        self.selector.register(fd, selectors.EVENT_READ, callback)
    
    def run_forever(self):
        while True:
            # 1. 执行就绪任务
            while self.ready:
                task = self.ready.popleft()
                task()
            
            # 2. 等待IO事件
            events = self.selector.select(timeout=0)
            for key, mask in events:
                callback = key.data
                self.ready.append(callback)

实际asyncio的实现要处理更多细节:

  • 每个socket关联一个Future对象
  • 协程通过await挂起时,会注册到selector
  • IO就绪时,事件循环将对应的Future设为完成状态
  • 调度器恢复协程执行

真正的asyncio在Linux下默认用epoll,BSD用kqueue,都通过selectors模块统一接口。Windows用IOCP,但Python通过proactor事件循环支持。

总结:asyncio本质是IO多路复用+协程调度的组合拳。

asynico 跟 多个客户端建立连接之后,服务端如何主动跟客户端发送 tcp 包呢?

直接创建一个 task, 然后在里面写逻辑就行了,

create_task(muti_handler(client_socket))

更多是通过 epoll 来调度你的服务器处理函数, 想清楚怎么调度就好了…

我写的这个, 就是不管客户端发什么过来, 我都直接 return html, 其实处理逻辑都可以和以前一样的

回到顶部