0

PROBLEM

I have 2 functions in my discord bot which takes no argument and calls another functions internally and finally returns a list. I dont know how to run both the functions at the same time which will help me make the overall feature a bit faster as these two function are the major time taking functions.

CODE

img = cv.imread('card.png')
def func1()
    #some code of cropping the above image as per my need
    char_list = [ocr(img1), ocr(img2), ocr(img3)] # these are the cropped 3 images and the ocr() function extracts the text from them
    return char_list

def func2()
    #some code of cropping the above image as per my need
    series_list = [ocr(img1), ocr(img2), ocr(img3)] # these are the cropped 3 images and the ocr() function extracts the text from them
    return series_list

ClawX69
  • 73
  • 1
  • 7
  • you can run two function with async programming. In python you can use asyncio library. See this document https://docs.python.org/3/library/asyncio.html – Navid Jan 21 '22 at 15:51

2 Answers2

1

It looks like your ocr function is blocking, meaning that when you run it, the current thread is blocked (and nothing else can run at the same time).

The solution is to run the blocking code (your func1 and func2 functions) in an executor. This StackOverflow answer explains it better than I can.

Here's a quick summary in case the link goes dead.

# Import the libraries you need (they should all be in the standard library, so you don't need to pip install anything)
import concurrent.futures
import asyncio

# Set up a ThreadPoolExecutor, which manages the Threads that are used later
# max_workers is the maximum number of threads to have running at once.
executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

async def in_your_command_or_some_other_async_function():
    # executor is in the global scope, so you are able to access it here
    # if you split your code in multiple files, you'll need to find a way to pass it to this function
    # DONT create a new ThreadPoolExecutor every time this function is called
    loop = asyncio.get_event_loop()
    results = await asyncio.gather(
        loop.run_in_executor(executor, func1, ARGUMENTS_TO_PASS_TO_FUNC1),
        loop.run_in_executor(executor, func2, ARGUMENTS_TO_PASS_TO_FUNC2)
    ) # You can add more functions to run at the same time if you need to
    # Results from func1 should be in index 0 of the variable results
    # Results from func2 should be in index 1 of the variable results
PythonPro
  • 291
  • 2
  • 11
  • I tried implementing this but getting this error `TypeError: gather() got an unexpected keyword argument 'fs'` – ClawX69 Jan 23 '22 at 09:34
  • @ClawX69 I've checked the docs of `asyncio.gather` and updated my answer. Can you try it again? – PythonPro Jan 25 '22 at 05:39
-1

It looks like you want something like this

import asyncio


async def func1():
    #some code of cropping the above image as per my need
    char_list = [ocr(img1), ocr(img2), ocr(img3)] # these are the cropped 3 images and the ocr() function extracts the text from them
    return char_list

async def func2():
    #some code of cropping the above image as per my need
    series_list = [ocr(img1), ocr(img2), ocr(img3)] # these are the cropped 3 images and the ocr() function extracts the text from them
    return series_list

async def event():
    results = await asyncio.gather(func1,func2,)

This will await for the results of func1 and func2 before continuing. Refer to here for more info on asyncio.gather

  • I did use your solution but could not achieve speed. I think it still runs two function simultaneously and not parallel – ClawX69 Jan 21 '22 at 17:01