如何使用 asyncio.to_thread 在单独的线程中运行 CPU 绑定的异步函数?

问题描述 投票:0回答:1

我正在使用异步任务对第 3 方库进行多次调用,该任务封装在函数 run_task 中,该函数是 CPU 密集型的。

我尝试使用 asyncio.to_thread 在单独的线程中运行它,但出现错误

这是我的代码的简化、正确版本,使用 shazamio。

import asyncio
from shazamio import Shazam

async def run_task(shazam):
    ret = await asyncio.to_thread(shazam.recognize_song, '01 - Forest Drive West - Impulse.mp3')
    print(ret)
    return 1 

async def run_all_tasks(iters):
    shazam = Shazam()
    loop = asyncio.get_event_loop()

    coros = [run_task(shazam) for i in range(iters)]
    await asyncio.gather(*coros)
    return 

if __name__ == '__main__':
    asyncio.run(run_all_tasks(10))

有了这个,我得到 ret 是一个协程,所以等待不起作用。我也收到这些警告

<coroutine object Shazam.recognize_song at 0x11054bf10>
/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py:1936: RuntimeWarning: coroutine 'Shazam.recognize_song' was never awaited
  handle = self._ready.popleft()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
python-3.x asynchronous async-await python-asyncio
1个回答
0
投票

您收到的错误表明

.recognize_song
本身已经被编写为协同例程。 (确实如此,如文档中所示:https://github.com/dotX12/ShazamIO

另一方面。

.to_thread
调用期望接收常规Python函数,它将生成另一个线程并在那里运行(并使用某种内部机制检索返回值)。

发生的事情是调用

.to_thread
,它调用协同例程方法
.recognize_song
,该方法立即返回一个可等待对象 -
.to_thread
不检查它,并将其作为调用“的结果返回”阻止”方法。

这种情况下的修复很简单:只需直接等待

shazam.recognize_song
调用即可。

顺便说一句,这不是本地的“CPU 密集型任务”:它所做的是使用 Shazam API 远程识别您的歌曲 - 它尽可能地受 I/O 限制。是的,远程 API 将执行 CPU 密集型工作,但在主机数据中心的远程 CPU 上。

© www.soinside.com 2019 - 2024. All rights reserved.