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
IVeverKB
V2EX  ›  Python

新手 关于 Python 协程的一个问题

  •  
  •   IVeverKB · 2020-12-07 11:27:01 +08:00 · 2479 次点击
    这是一个创建于 1453 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大概意思是这样的,协程里面有一个无线循环 A,主进程也就是下面写的 print main loop 是个无线循环 B 。有没有什么方法是 A 和 B 循环可以交替执行的?因为我现在发现只有让 A 一直跑或者 A 做完了才能做 B,但是因为它们俩都是死循环就没法实现同时交替执行。

    或者是不是我要实现 A 和 B 交替循环只有把 A 写成多线程才行?前提是我不想把 B 写进另一个协程或线程里,我只想让它保留在主进程这个地方。

    多谢

    import asyncio
    import time
    
    async def my_async():
    	while True:
        		await asyncio.sleep(0.5)
            	print("in my_async loop")
    
    
    loop = asyncio.get_event_loop()
    loop.crate_task(my_async())
    
    loop.run_forever()
    #loop.run_until_complete(my_async())
    
    while True:
    	time.sleep(0.5)
    	print("in the main loop")
    
    14 条回复    2020-12-07 22:54:12 +08:00
    111111111111
        1
    111111111111  
       2020-12-07 11:36:08 +08:00 via Android
    因为实际上是单线程的,下面的 while 要等上面的代码执行完了才有机会执行。
    或许可以试试 yield 关键字?

    你说的“不想把 B 写进另一个协程或线程里,我只想让它保留在主进程这个地方” 你可以说说具体的原因,这里只有一个进程一个线程,没什么主不主的
    sujin190
        2
    sujin190  
       2020-12-07 11:39:50 +08:00
    把 B 也用协程就是了啊,协程调度本来就独占整个线程的
    Vegetable
        3
    Vegetable  
       2020-12-07 11:41:14 +08:00
    按你说的没办法,你这个设计有问题,要不就 A 进独立线程,要不就 ab 都在一个 event loop 里
    fasionchan
        4
    fasionchan  
       2020-12-07 11:45:35 +08:00
    协程需要由事件循环驱动,如果主线程执行了事件循环,就没有机会执行外部的 while True,如果执行了 while True,就无法执行事件循环。
    IVeverKB
        5
    IVeverKB  
    OP
       2020-12-07 11:54:02 +08:00
    @111111111111 #1
    @sujin190 #2
    我是把业务需求简化了才这么说的。现在是想要在 django 启动的时候开一个协程或线程同时处理一下其他事情,django 本身对我来说就相当于 B 循环,所以我就这么问了。实际上是我不会把 B,也就是 django 本身业务写成一个协程。不知道这么说容易理解不。
    IVeverKB
        6
    IVeverKB  
    OP
       2020-12-07 11:58:17 +08:00
    @Vegetable #3
    @fasionchan #4
    感谢,明白了协程肯定做不了这个了
    NeilWang
        7
    NeilWang  
       2020-12-07 12:27:29 +08:00
    真的想使用协程运行任务 A 的话,其实可以在 django 启动前启动一个子线程,在子线程中创建一个新的事件循环,然后把协程 A 在这个事件循环里运行。

    ```
    import asyncio
    import time
    import threading


    async def my_async():
    while True:
    await asyncio.sleep(0.5)
    print("in my_async loop")


    _event_loop = asyncio.new_event_loop()


    def run_event_loop():
    _event_loop.run_forever()


    threading.Thread(target=_event_loop.run_forever, daemon=True).start()

    # 将新的事件循环设置为当前线程的事件循环,这样后续在当前线程中可以使用 asyncio.get_event_loop() 得到 _event_loop
    asyncio.set_event_loop(_event_loop)

    # 事件循环不在当前线程,需要使用 run_coroutine_threadsafe 提交协程任务
    asyncio.run_coroutine_threadsafe(my_async(), asyncio.get_event_loop())

    while True:
    time.sleep(0.5)
    print("in the main loop")
    ```

    这样的话,在 django 中处理视图逻辑时也是可以提交协程任务到事件循环的
    IVeverKB
        8
    IVeverKB  
    OP
       2020-12-07 14:51:58 +08:00
    @NeilWang #7
    非常感谢!提供了新思路,这个想法也太妙了哈哈
    keepeye
        9
    keepeye  
       2020-12-07 15:00:27 +08:00
    A 也转换成异步的 然后 asyncio.gather(A(), B())

    A 里面 sleep 换成 asyncio.sleep
    no1xsyzy
        10
    no1xsyzy  
       2020-12-07 15:08:17 +08:00
    我怀疑你应当寻求 Celery 一类任务框架

    顺便一提,loop.run_forever() 本身就可以理解为一个 while 循环。
    sujin190
        11
    sujin190  
       2020-12-07 15:33:21 +08:00
    @IVeverKB #5 你需要的是 celery
    IVeverKB
        12
    IVeverKB  
    OP
       2020-12-07 16:51:22 +08:00
    @NeilWang #7
    能否再追问一下,这个子线程写在 django 项目的哪个文件中比较好呢,就是能做到不影响 django 本项目的运行但同时还能被顺利执行到(且只会被执行一次,因为之前有看到写在 urls.pyviews.py 中会因为部署在 uwsgi+nginx 而产生多进程执行多次)?目前两个备选,一个是 project 目录下的__init__.py 文件,或者是 wsgi.py 文件,不知道是否满足我的需求?
    ClericPy
        13
    ClericPy  
       2020-12-07 22:04:54 +08:00
    交替执行... 两个任务的话, 办法挺多的, yield 生成器 / 或者互相 yield / asyncio.Event, 但是具体哪个能用还是看具体场景, 你这例子都没举全, 也没法给你调试个代码出来
    SaltCat
        14
    SaltCat  
       2020-12-07 22:54:12 +08:00
    用 asyncio.Lock,还有就直接 asyncio 技术栈一把嗦吧,asyncio 的侵入性感觉还是太强了。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2628 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 01:49 · PVG 09:49 · LAX 17:49 · JFK 20:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.