关于协程转线程的一个问题

2020-12-02 19:28:08 +08:00
 abersheeran

原始问题在这 https://github.com/abersheeran/a2wsgi/issues/7

代码在这 https://github.com/abersheeran/a2wsgi/blob/55ac9c4b82c6988aa4a8280cfc3fadd2565ed37a/a2wsgi/asgi.py

我的思路是实现一对 Event,协程里传数据给 WSGI 线程,然后 WSGI 线程传数据给协程。之前工作的一直还行,直到那个 issue 的用例里,两个协程分别读和写,导致第一个写的消息被覆盖了。

我昨天花了一整个晚上也没想到一个优雅的解决方案。所以发出来请教一下大家,有没有“简洁优雅”的解决方案。

2186 次点击
所在节点    Python
9 条回复
SaltCat
2020-12-02 22:34:00 +08:00
感觉你的表述并不清楚: 你没有说是如何从 coroutine send msg 到 thread 进行处理的(try contextvars); 第一个写的消息被覆盖, 是否考虑使用类似 stack 这样的数据结构 + property 防止覆盖? 如果涉及到同 /异步上下文传递, 可以考虑 `contextvars` 这个库: asyncio 在执行协程时会复制一份当前的上下文来执行, 从而避免出现覆写的问题;
希望能解决你的问题.
linw1995
2020-12-03 10:03:07 +08:00
这个 async_event 及 sync_event 每次产生都是一对对的吗?每次 send 或者 receive 生成一个 Event (或者一对)就好了。
linw1995
2020-12-03 10:18:26 +08:00
仔细看了一遍,题主应该是需要用个 queue 把 sync_event 串行起来吧。这样就不会先处理第二个消息了。
abersheeran
2020-12-03 10:24:52 +08:00
@linw1995 如果用 Queue 串行的话,在 coroutine 里往 threading.Queue 写数据的时候怎么异步等待呢?因为默认是同步等待的,会阻塞 send 、receive 协程。

@SaltCat 谢谢你的建议,不过这不是问题所在。
linw1995
2020-12-03 10:52:13 +08:00
@abersheeran aio-libs 有个库叫 janus 应该能满足你的要求。

https://github.com/aio-libs/janus
abersheeran
2020-12-03 11:02:44 +08:00
@linw1995 感谢!看起来可以解决我的问题,我看看他代码怎么做的。
linw1995
2020-12-03 23:52:11 +08:00
@abersheeran 今天发现了一个和你开发的,功能一样的轮子 https://github.com/django/asgiref
abersheeran
2020-12-04 00:42:20 +08:00
@linw1995 兄弟你是在开玩笑嘛…… asgiref 是 ASGI 标准库。里面肯定是有实现 WSGI 到 ASGI 的转换的啊!但是是个参考实现,仅仅是”可用“,速度很差劲,而且会预读 request body,大文件一来它就死了(同理,uvicorn 、starlette 里面自带的也一样)。你可以看看 a2wsgi 项目里提供的 benchmark 。

再告诉你一个秘密,如果你看看 asgiref 贡献者名单,你会发现我也在里面😀zero-copy send 这个拓展标准是我制定的。
linw1995
2020-12-04 09:47:43 +08:00
@abersheeran 233 我对这方面都不关注的。这个库是在 mitmproxy 源码里发现的,还以为这个普通轮子。原来是根正苗红的官方轮子_(:_」∠)_

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/731498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX