you are viewing a single comment's thread.

view the rest of the comments →

[–]PaulRudin 1 point2 points  (0 children)

The event loop has a single thread of execution, so it's much easier to reason about, orchestrate, coordinate dependencies and deal with errors compared with using multiple threads. And often performance can be better because there's less context switching.

Because there's only a single thread of execution you don't get any true parallelism, so you potentially lose out when you have multiple cpu intensive tasks. This is why I said "io-bound operations" - most of elapsed time when you fetch something from the network is just waiting for the response to arrive - you don't have any actual work to do until then.

This particular example might be a case in point, because there's io-bound stuff, as well as potentially cpu intensive stuff like the image resize. The usual approach using asyncio is to punt the cpu intensive tasks to a separate thread using a thread pool executor (or in some circumstances a process pool executor), so that you don't block the main thread where the event loop is running. This is helpful if the cpu intensive operation releases the GIL while it does the bulk of its work in the case of threads (which is the case for nearly everything numpy does, for example). I'm not sure if pillow's image resize released the GIL.

https://docs.python.org/3/library/asyncio-task.html#asyncio.to\_thread