Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is run_in_executor optimized for running in a loop with coroutines?

It strikes me that the run_in_executor() method of the asyncio library belongs to a loop object.

In particular, what would be the difference if I chose to run a second thread alongside an async event loop the "usual" way, by import threading, t = threading.Thread(target=...), t.start()?

Perhaps the answer is by using the asyncio module there are low level optimizations which can be made at runtime if the loop knows about additional threads?

like image 395
sphere Avatar asked Mar 06 '19 16:03

sphere


People also ask

What is Loop Run_in_executor?

run_in_executor is used to manage threads from within an event loop. To this end, it needs to wrap the thread into a Future, which needs to be assigned to an event loop (in one way or another). The reason the method is stored directly in a loop object is probably historical.

How do you stop a running event loop?

Run the event loop until stop() is called. If stop() is called before run_forever() is called, the loop will poll the I/O selector once with a timeout of zero, run all callbacks scheduled in response to I/O events (and those that were already scheduled), and then exit.

What is Asyncio event loop?

Introduction to Python Event Loop. Python Event Loop is the centre of each asyncio application. Occasion circles, run offbeat assignments and callbacks, perform arrange IO activities, and run subprocesses. Python Event Loop is useful to deal with all the occasions in a computational code.

How do I stop Asyncio event loop?

Run an asyncio Event Loop run_until_complete(<some Future object>) – this function runs a given Future object, usually a coroutine defined by the async / await pattern, until it's complete. run_forever() – this function runs the loop forever. stop() – the stop function stops a running loop.


Video Answer


1 Answers

You can always start another thread manually, but then you are responsible for giving it work, e.g. using a queue. In Python 3 concurrent.futures provide a convenient API for offloading tasks to a thread pool, which it calls executor. Its submit method takes a function, gives it to a thread in the pool to run it, and immediately returns a handle that will provide the result (or propagate an exception) when it is ready.

run_in_executor delivers the same convenience to asyncio. Remember that you're not supposed to run any blocking code inside asyncio - for example time.sleep() is forbidden, because it blocks the whole event loop. run_in_executor allows you to side-step that rule. For example:

async def sleep_test():
    loop = asyncio.get_event_loop()
    print('going to sleep')
    await loop.run_in_executor(None, time.sleep, 5)
    #time.sleep(5)
    print('waking up')

async def parallel():
    # run two sleep_tests in parallel and wait until both finish
    await asyncio.gather(sleep_test(), sleep_test())

asyncio.run(parallel())

Running this code shows that both instances of the coroutine sleep in parallel. If we used time.sleep() directly, they would sleep in series because the sleep would block the event loop.

This example is of course silly because there is asyncio.sleep() that suspends a coroutine without spending a slot in a thread pool, but it shows the basic idea. Realistic use cases for run_in_executor include:

  • integrating CPU-bound code, such as numpy or pandas calculations, into an asyncio program
  • invoking legacy code that hasn't yet been ported to asyncio
  • blocking calls where non-blocking APIs are simply unavailable - e.g. proprietary database drivers, or blocking OS-level calls such as those for file system access
like image 193
user4815162342 Avatar answered Sep 29 '22 18:09

user4815162342