【问题标题】:Asyncio "fire and forget" tasks in a separate threadAsyncio 在单独的线程中“触发并忘记”任务
【发布时间】:2020-07-27 03:52:20
【问题描述】:

我有一个长时间运行的同步 Python 程序,我希望每秒运行大约 10 个“即发即弃”的任务。这些任务命中远程 API,不需要返回任何值。我尝试了this answer,但它需要太多的 CPU/内存来生成和维护所有单独的线程,所以我一直在研究 asyncio。

This answer 很好地解释了如何使用 asyncio 运行“一劳永逸”。但是,它需要使用run_until_complete(),它会等待所有异步任务完成。我的程序正在使用同步 Python,所以这对我不起作用。理想情况下,代码应该像这样简单,log_remote 不会阻塞循环:

while True:
    latest_state, metrics = expensive_function(latest_state)
    log_remote(metrics) # <-- this should be run as "fire and forget"

我使用的是 Python 3.7。如何在另一个线程上使用 asyncio 轻松运行它?

【问题讨论】:

    标签: python multithreading python-asyncio fire-and-forget


    【解决方案1】:

    您可以在单个后台线程中启动单个事件循环,并将其用于您的所有即发即弃任务。例如:

    import asyncio, threading
    
    _loop = None
    
    def fire_and_forget(coro):
        global _loop
        if _loop is None:
            _loop = asyncio.new_event_loop()
            threading.Thread(target=_loop.run_forever, daemon=True).start()
        _loop.call_soon_threadsafe(asyncio.create_task, coro)
    

    有了这个,你就可以在通过调用async def创建的协程对象上调用fire_and_forget

    # fire_and_forget defined as above
    
    import time
    
    async def long_task(msg):
        print(msg)
        await asyncio.sleep(1)
        print('done', msg)
    
    fire_and_forget(long_task('foo'))
    fire_and_forget(long_task('bar'))
    print('continuing with something else...')
    time.sleep(3)
    

    请注意,log_remote 需要使用 asyncio、aiohttp 而不是请求等实际编写为 async def

    【讨论】:

    • 这不是每次都创建一个新线程而不是使用一个连续运行的单独线程吗?
    • @Alexis.Rolland 不,fire_and_forget() 只会在第一次调用时小心地创建/启动新线程。
    猜你喜欢
    • 2021-04-17
    • 2016-06-21
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    相关资源
    最近更新 更多