0

Can the eventloop switch between coroutines:

  • when async method is awaited (called), before it executes?
  • when async method is awaited (called), after it executes?

Here is an example:

async def some_slow_method():
    total = 0.0
    for i in range(1, 10000):
        for j in range(1, 10000):
            total += (i / j)
    return total

async def the_caller():
    # can the evenloop switch to another coroutine, between here...
    result = await some_slow_method()
    # ...and here?

(I find the documentation unclear on exactly this point)

Helgi Borg
  • 835
  • 10
  • 32

1 Answers1

2

The event loop can't switch to other coroutines await unless the awaited coroutine (or other awaitable) chooses to suspend. Since some_slow_method doesn't contain a single await, it will never suspend and therefore the_caller() will never switch to another coroutine. The fact that the event loop doesn't always suspend on await is sometimes a source of bugs, as discussed here.

You can force some_slow_method to occasionally switch to other coroutines using await asyncio.sleep(0), but that is considered bad style because the asyncio thread should avoid doing CPU work. If you must do CPU-bound work, a better option is to make some_slow_method an ordinary def and run it using await loop.run_in_executor(None, some_slow). This will hand it off to a thread pool, suspend the current coroutine, and wake it up once the function has completed, transferring its return value (or exception if one was raised).

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • Thanks for the answer! I was almost certain that this was the case but couldn’t find it anywhere in the docs. This is important when it comes to synchronization e.g. in Rest services such that only request at a time gets to do a complex update, etc. – Helgi Borg Jul 29 '20 at 11:17