Abhishek Lakra
Abhishek Lakra

Reputation: 11

How to implement async method in python

I want to implement async method in the following code:

import time

def main(num):
    num_list = []
    for i in range(num):
        num_list.append(i)
        print("The number that is added in list is:", i)
        time.sleep(2)
    return num_list


def count():
    start_time = time.time()
    num_list = [3,5,2,8,2]
    for i in num_list:
        print("\nIn count() = ", i)
        data = main(i)
        print("Got data from main() = ", data)
        time.sleep(2)
    total_time = time.time() - start_time
    print("The code took",total_time,"seconds to complete")

if __name__ == "__main__":
    count()

This code takes 50s to complete. I tried to implement async method in this code but I was not able to succeed because I just started learning about it. Can you tell me how can I implement async method in this code.

Here's the code where I tried to implement async method:

import asyncio, time
from asgiref.sync import sync_to_async

@sync_to_async
def main(num):
    num_list = []
    for i in range(num):
        num_list.append(i)
        print("The number that is added in list is:", i)
        time.sleep(2)
    return num_list

def get_data(data_var):
    try:
        data_var.send(None)
    except StopIteration as e:
        return e.value


async def count():
    start_time = time.time()
    num_list = [3,5,2,8,2]
    for i in num_list:
        print("In count() :".format(i))
        task1 = asyncio.ensure_future(main(i))
        data = get_data(main(i))
        print("In main() = {}".format(data))
        await asyncio.sleep(2)
        await task1
    total_time = time.time() - start_time
    print("The code took",total_time, "seconds to complete")

if __name__ == "__main__":
    asyncio.run(count())

And I am not getting num_list as return value instead I am getting None.

Upvotes: 1

Views: 1225

Answers (1)

t2o2
t2o2

Reputation: 445

If you can convert your main into async function, then it can be written as this.

import asyncio
import time
from loguru import logger


async def main(num):
    num_list = []
    for i in range(num):
        num_list.append(i)
        logger.info(f"The number that is added in list is: {i}")
        await asyncio.sleep(2)
    return num_list


async def count():
    start_time = time.time()
    num_list = [3,5,2,8,2]
    task_list = []
    for i in num_list:
        logger.info(f"In count() = {i}")
        task = asyncio.create_task(main(i))
        task_list.append(task)
    result_list = await asyncio.gather(*task_list)
    for r in result_list:
        logger.info(f"Got data from main() = {r}")
    total_time = time.time() - start_time
    logger.info(f"The code took {total_time} seconds to complete")

loop = asyncio.get_event_loop()
loop.run_until_complete(count())

If you can't convert the main function, threading is your best bet.

from concurrent.futures import ThreadPoolExecutor, as_completed
from loguru import logger

def main(num):
    num_list = []
    for i in range(num):
        num_list.append(i)
        logger.info(f"The number that is added in list is: {i}")
        time.sleep(2)
    return num_list


def count():
    start_time = time.time()
    num_list = [3,5,2,8,2]
    with ThreadPoolExecutor(max_workers=5) as executor:
        futures = {}
        for k in num_list:
            logger.info(f"In count() = {k}")
            futures[executor.submit(main, k)] = k
        for future in as_completed(futures):
            logger.info(f"Got data from main() = {future.result()}")
            time.sleep(2)
        total_time = time.time() - start_time
        logger.info(f"The code took {total_time} seconds to complete")

count()

Both will achieve the same goal in terms of overall execution time.

Upvotes: 1

Related Questions