V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
abersheeran
V2EX  ›  Python

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

  •  
  •   abersheeran ·
    abersheeran · 2020-12-02 19:28:08 +08:00 · 1991 次点击
    这是一个创建于 1212 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    第 1 条附言  ·  2020-12-04 00:46:05 +08:00
    已经解决了……在看完那个让我感觉十分复杂的同步异步队列之后,我想起来,直接给协程加个异步锁,同一个 WSGI 线程对应的数据,同一时间只允许一个协程进行操作就完事了,反正就算你协程写了七八条,同步线程这边还得按照顺序处理,不如让协程等着别动,等同步处理完再动。
    9 条回复    2020-12-04 09:47:43 +08:00
    SaltCat
        1
    SaltCat  
       2020-12-02 22:34:00 +08:00
    感觉你的表述并不清楚: 你没有说是如何从 coroutine send msg 到 thread 进行处理的(try contextvars); 第一个写的消息被覆盖, 是否考虑使用类似 stack 这样的数据结构 + property 防止覆盖? 如果涉及到同 /异步上下文传递, 可以考虑 `contextvars` 这个库: asyncio 在执行协程时会复制一份当前的上下文来执行, 从而避免出现覆写的问题;
    希望能解决你的问题.
    linw1995
        2
    linw1995  
       2020-12-03 10:03:07 +08:00
    这个 async_event 及 sync_event 每次产生都是一对对的吗?每次 send 或者 receive 生成一个 Event (或者一对)就好了。
    linw1995
        3
    linw1995  
       2020-12-03 10:18:26 +08:00
    仔细看了一遍,题主应该是需要用个 queue 把 sync_event 串行起来吧。这样就不会先处理第二个消息了。
    abersheeran
        4
    abersheeran  
    OP
       2020-12-03 10:24:52 +08:00
    @linw1995 如果用 Queue 串行的话,在 coroutine 里往 threading.Queue 写数据的时候怎么异步等待呢?因为默认是同步等待的,会阻塞 send 、receive 协程。

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

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

    再告诉你一个秘密,如果你看看 asgiref 贡献者名单,你会发现我也在里面😀zero-copy send 这个拓展标准是我制定的。
    linw1995
        9
    linw1995  
       2020-12-04 09:47:43 +08:00
    @abersheeran 233 我对这方面都不关注的。这个库是在 mitmproxy 源码里发现的,还以为这个普通轮子。原来是根正苗红的官方轮子_(:_」∠)_
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3531 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 04:50 · PVG 12:50 · LAX 21:50 · JFK 00:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.