0

I'm making multiple calls to a 3rd party lib using asyncio tasks, wrapped in a function run_task, which is CPU intensive.

I tried using asyncio.to_thread to run it in a separate thread but I am getting errors

Here is a simplified, correct version of my code, using 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))

With this I get ret is a coroutine, so the await did not work. I also get these warnings

<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
7
  • asyncio.to_thread takes a function as an argument, not a coroutine. It's asyncio.to_thread(shazam.recognize_song, 'SomeFile.mp3') Commented Nov 25, 2023 at 19:54
  • Thanks, I corrected this mistake and but i still don't understand the behaviour. I edited the question so that it is clearer and general Commented Nov 25, 2023 at 20:02
  • I'm finding that i get the correct behaviour when i replace the shazam.recognize_song by time.sleep, but with asyncio.sleep i get the same weird behaviour and warning Commented Nov 25, 2023 at 20:13
  • Oh shazam.recognize_song does return a coroutine that you could just await already? Then you should not use to_thread at all! asyncio.to_thread takes a synchronous function as its argument, not a coroutine function. Commented Nov 25, 2023 at 20:23
  • 1
    I found the solution here stackoverflow.com/questions/59645272/… Commented Nov 25, 2023 at 20:47

1 Answer 1

0

What the error you are getting says is that the .recognize_song itself is already written as a co-routine. (and indeed it is, as can be seen in the docs: https://github.com/dotX12/ShazamIO )

On the other hand. the .to_thread call expect to receive regular Python functions it will spawn another thread and run there, (and retrieve the return value by using some internal mechanism).

What is taking place is that .to_thread is called, it calls the co-routine method .recognize_song, which imediatelly returns an awaitable object - .to_thread doesn't check it, and return it as the result of calling the "blockin" method.

The fix in this case is trivial: just await for the shazam.recognize_song call directly.

BTW, this is not a "CPU intensive task" locally: what it does is to use the Shazam API to remotely identify your song- it is as I/O bound as it can. The remote API, yes, will do CPU intensive work, but on remote CPUs in the host's datacenter.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for clarifying the asyncio concepts ! The trivial fix is what i had in the first place, but it looked like the code ran synchronously: linear time in number of calls all prints happening at the same time at the end of the program. But if I understand your answer correctly, that's not an issue with how the code is written

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.