最近对比了各种 ASGI 服务器,发现当前的几个 ASGI 服务器中 ,hypercorn 的完成度是最高的,http 支持到 3,ASGI 扩展也支持了两个,可惜 Zero Copy Send 目前还没支持,当时就想对他加入这个的支持,如果成功,这也是第一个支持全部 ASGI 扩展的 ASGI 服务器,然而 hypercorn 原作者似乎最近没空,我就自己 fork 了个,主要代码在这,https://gitlab.com/synodriver/hypercorn/-/blob/zerocopy/src/hypercorn/asyncio/tcp_server.py#L106, 但是测试中发生了问题,在 debian 上 Errno32 Brokenpipe,在 win 上客户端也是收不到数据,似乎一旦调用 loop.sendfile,对面就关闭了连接。有对 ASGI 协议和服务器有研究的大佬可以帮忙看看吗?
这是我用的测试 code
async def app2(scope, receive, send):
if scope["type"] == "http" and scope["path"] == "/":
await send({"type": "http.response.start", "status": 200,
"headers": [(b"Content-Type", b"image/png"), (b"Cache-Control", b"no-cache")]})
f = open(r"test.jpg", "rb")
await send({"type": "http.response.zerocopysend", "file": f.fileno()})
1
abersheeran 2021-10-05 21:26:42 +08:00 1
GitHub 上向我们提问的原来是你……这个扩展是我设计的,设计之初我想的是追求极致的性能——用 C 、Rust 实现的服务器接受一个文件描述符远比接受一个 PyObject 要更方便处理。
这里你应该用 os.sendfile 而不是 loop.sendfile |
2
abersheeran 2021-10-05 22:38:28 +08:00
看到你这个帖子之后我想起来之前 uvicorn 的维护者问我有没有空帮忙实现这个扩展,刚刚写了一下 https://github.com/encode/uvicorn/pull/1210 。你参考参考吧。
|
3
jianhaochende OP 感谢回复。我给 hypercorn 用上后,显示是已经发送成功了,但是浏览器并没有收到,发送文件过大时甚至出现 lockingIOError: [Errno 11] Resource temporarily unavailable,很迷惑。hypercorn 只有 h11 h2 h3 的解析器,没有 httptools 的
|
4
jianhaochende OP |
5
haoliang 2021-10-06 00:21:47 +08:00
@abersheeran 这个 pr 中 `async send(): ... os.sendfile()`, 看起来一旦有一个 request 的 coroutine 中触发了 `os.sendfile` 那么整个程序的其他 coroutine 就一直 block ?
或许是我漏看了哪里,我之前也在异步程序中使用 `os.sendfile` 当时是借助单独的线程(池) |
6
abersheeran 2021-10-06 02:20:15 +08:00
@haoliang os.sendfile 不会阻塞。
|
7
jianhaochende OP @abersheeran 请问使用 h11 的不能实现是和 h11 自身的状态机有关吗?
|
8
abersheeran 2021-10-06 14:30:25 +08:00
@jianhaochende 对。我想了一下,如果你真要在 h11 里实现,只能在 sendfile 之后生成等长度的空白 bytes 丢给 h11,性能会差很多,不过还是要比一点点读文件去发送要快。你可以试试。
|
9
haoliang 2021-10-07 13:50:48 +08:00
有个 h11.Connection.send_with_data_passthrough 方法,不需要构造等长度的数据块
* https://h11.readthedocs.io/en/latest/api.html#h11.Connection.send_with_data_passthrough |
10
jianhaochende OP 感谢,目前已经在 hypercorn 中实现了。
说来当初弄这个原因就是想搞个完美的 ASGI 服务器,也是看着一堆拉胯的 ASGI 服务器为 python 着急,ASGI 框架的性能比的就是 ASGI 服务器的性能,然而官方的实现并不怎么出色。Daphne,自称是 ASGI 的参考实现,快 3 年了,lifespan 连影子都没有,但依赖一大堆,又慢又重。uvicorn 对 http/2 不感兴趣也是他们作者说的,看起来还算有希望的就剩 hypercorn 和 nginx unit 了。hypercorn 功能最多,基本上完整实现了 ASGI 规范的全部东西,简直是 ASGI 的希望,unit 是 nginx 推动的,纯 C 实现,速度比 uvicorn 还快,也是未来的希望之一。真心希望这几个服务器能发展起来,也算是对异步生态的贡献了。 |