首页 > 解决方案 > 使用 asyncio 而不是线程处理多个元素

问题描述

我有一个程序使用这样的 python 线程:启动 5 个线程并开始处理元素列表。

def process_element(element):
   print(element)

jobs = Queue()
    
def do_stuff(q):
    while not q.empty():
        value = q.get()
        process_element(element=value)
        q.task_done()
 
for i in line: # my list of element
    jobs.put(i)
    
for i in range(5):
    worker = threading.Thread(target=do_stuff, args=(jobs))
    worker.start()

jobs.join()

我怎样才能asyncio用来做同样的工作。

标签: python-3.xpython-asyncio

解决方案


将您的代码直译为 asyncio 如下所示:

import asyncio, random

async def process_element(element):
    print('starting', element)
    await asyncio.sleep(random.random())  # simulate IO-bound processing
    print('done', element)

async def do_stuff(q):
    while not q.empty():
        value = await q.get()
        await process_element(element=value)
        q.task_done()

async def main():
    jobs = asyncio.Queue()

    for i in range(20):
        await jobs.put(i)

    for i in range(5):
        asyncio.create_task(do_stuff(jobs))

    await jobs.join()

asyncio.run(main())

但请注意:

  • Asyncio 处理 IO 密集型任务,例如与 HTTP 服务器或远程数据库、聊天服务器等通信。它不处理 CPU 密集型任务,长时间运行的操作将阻塞整个事件循环。(在这种情况下,多线程或多处理更合适。)因此,将多线程代码“转换”为 asyncio 通常会失败。

  • while not q.empty(): ... process ...在线程和异步中都是一种反模式,因为它不允许等待某些东西到达队列。如果您事先知道所有项目,则首先不需要队列,您可以使用普通列表。


推荐阅读