Atif Shafi
Atif Shafi

Reputation: 1194

how to run async function in Threadpoolexecutor in python

I have an async get_forecastweather function which gives me JSON weather data, I understand that we can't execute the async function inside sync, but how do i do it inside a separate thread, need help, thanks in advance

def weather_detail(request):
    if request.method == 'GET':
        city_name = 'my_city'
        key = 'mykey'
        result = None
        with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
            response = executor.submit(get_forecastweather,city_name,key)
            result = response.result()
        print('Result from thread ',result)
        return render(request,'weather/weather_detail.html')

the error I am getting is

 RuntimeWarning: coroutine 'get_forecastweather' was never awaited
  response = wrapped_callback(request, *callback_args, **callback_kwargs)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Upvotes: 3

Views: 6985

Answers (1)

Paul Cornelius
Paul Cornelius

Reputation: 10926

You can write a small wrapper function that runs your async routine in a separate thread and returns the result. You can simply use asyncio.run for this. The ThreadPoolExecutor mechanism will create the new threads for you, and the asyncio.run method will create a new event loop, run it, return the result and then close the loop. Here is an example program, where instead of your request for the weather I generate a random integer between two limits:

from concurrent.futures import ThreadPoolExecutor
import random
import time
import asyncio

# You would use weather_detail here
async def get_random(n0, n1):
    await asyncio.sleep(3.0)
    return random.randint(n0, n1)

def wrapper(coro):
    return asyncio.run(coro)

def main():
    print("Start", time.ctime())
    with ThreadPoolExecutor(max_workers=3) as executor:
        arglist = ((10, 20), (30, 40), (50, 60), (90, 100))
        coros = [get_random(n0, n1) for n0, n1 in arglist]
        for r in executor.map(wrapper, coros):
            print(r, time.ctime())
            
main()

# Output:
# Start Fri Sep 10 00:45:13 2021
# 15 Fri Sep 10 00:45:16 2021
# 40 Fri Sep 10 00:45:16 2021
# 52 Fri Sep 10 00:45:16 2021
# 99 Fri Sep 10 00:45:19 2021

I included time stamps to show the time delays, and prove that three threads are running in parallel. The first three calls to wrapper finish in 3 seconds but the fourth takes 3 more, since there are only three worker threads.

Upvotes: 7

Related Questions