3

I'm looking to run a heavy computing task in the background without blocking IO. Problem here is my main function does not depend on the heavy task and needs to return value before/while executing the heavy computing task. As an example:

def main(args):
   transformed_data_list:List[Dict] = translate_request_to_object(args)
   status = insert_data_into_db(transformed_data:Dict)
   if(status)
      # running background task
      asyncio.run(process_background_task(transformed_data_list))

   # Here, I want to return a success response as soon as data inserted into db
   return "data insert into db"
   async process_background_task(transformed_data_list:List[Dict]):
      for data in transformed_data_list:List:
         asyncio.create_task(heavy_computation_task(data))

But above code not returning response until process_background_task completed.

1 Answer 1

6

How to run task in background

asyncio.run is the blocking function that starts event loop. If you want to start process_background_task in background you need to use asyncio.create_task and make main asynchronous. Then run asyncio.run(main(...)).

async def main(args):
    transformed_data_list:List[Dict] = translate_request_to_object(args)
    status = insert_data_into_db(transformed_data:Dict)
    if status:
        # running background task
        asyncio.create_task(process_background_task(transformed_data_list))

    # Here, I want to return a success response as soon as data inserted into db
    return "data insert into db"


async def process_background_task(transformed_data_list:List[Dict]):
    for data in transformed_data_list:List:
        asyncio.create_task(heavy_computation_task(data))

# Start event loop, execute task and wait until task finish.
asyncio.run(main(...))

How to run heavy tasks in event loop

But in the case heavy_computation_task will block event loop you need to use ProcessPoolExecutor with loop.run_in_executor.

Here is the example from documentation:

import asyncio
import concurrent.futures

def cpu_bound():
    # CPU-bound operations will block the event loop:
    # in general it is preferable to run them in a
    # process pool.
    return sum(i * i for i in range(10 ** 7))

async def main():
    loop = asyncio.get_running_loop()

    # Run in a custom process pool:
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, cpu_bound)
        print('custom process pool', result)

asyncio.run(main())

In your case:

async def main(args):
    transformed_data_list:List[Dict] = translate_request_to_object(args)
    status = insert_data_into_db(transformed_data:Dict)
    if status:
        # running background task
        asyncio.create_task(process_background_task(transformed_data_list))

    # Here, I want to return a success response as soon as data inserted into db
    return "data insert into db"


async def process_background_task(transformed_data_list:List[Dict]):
    loop = asyncio.get_running_loop()

    for data in transformed_data_list:List:
        with concurrent.futures.ProcessPoolExecutor() as pool:
            await loop.run_in_executor(pool, heavy_computation_task, data)

# Start event loop, execute task and wait until task finish.
asyncio.run(main(...))
Sign up to request clarification or add additional context in comments.

4 Comments

Could you please why you suggest ProcessPoolExecutor instead of ThreadPoolExecutor ? And from where I call asyncio.run(main(...)) will again block that parent function, right?
ThreadPoolExecutor can run simultaneously only one task, so it only suits IO-bound operations, but not CPU-bound operations. ProcessPoolExecutor can run many tasks simultaneously.
asyncio.run(main(...)) will block the function where it runs.
As noted in the docs, you should probably save a reference to the result of create_task function, to avoid task disappearance mid-execution due to garbage collection.

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.