SAL
SAL

Reputation: 545

Running a function blocks the bot - discord.py

I was trying to search data from four files (they're 4GB large) using a command typed on discord. The execution time of the search function takes about ten minutes to iterate through the 4 files; when I tried to type the command twice in a row, the second command get executed after the first command get executed (about 10 minutes later).

def main(self):
    @self.client.command()
    async def fsearch(ctx, *args):
        self.client.loop.create_task(self.searchTask(ctx, *args)) 

self.searchTask is the searching function.

Is there any idea to let the function execute without blocking the bot? (after a while the bot goes offline during the execution.)

Update:

This is a code snippet from the self.searchTask function:

async def searchTask(self, ctx, *args):
    found = False
    name = args[0].lower().
    surname = args[1].lower()
    await ctx.send("Searching data...")
    with open(f"{CURRENT_DIR}/out.txt", "w") as fwrite:
        flist = os.listdir(f"{CURRENT_DIR}/datab")
        for x in flist:
            with open(f"{CURRENT_DIR}/datab/{x}", "rb") as f:
                for line in f:
            ...


   fwrite.close()
   if found:
       await ctx.send("Done! Here's the result:")
       await ctx.send(file=discord.File(f"{CURRENT_DIR}/out.txt"))
   else:
       await ctx.send("Can't find data")

Upvotes: 0

Views: 1546

Answers (1)

thisisalsomypassword
thisisalsomypassword

Reputation: 1611

You cannot have blocking functions in asynchronous code. It seems searchTask is blocking and so your event loop is grinding to a halt. Asyncio event loops provide a simple API for running blocking functions in a threadpool or processpool to keep them from blocking your event loop.

EDIT: Example: Run file operations in thread

def search_files():
    found = False
    flist = os.listdir(f"{CURRENT_DIR}/datab")
    for x in flist:
        with open(f"{CURRENT_DIR}/datab/{x}", "rb") as f:
            for line in f:
                found = found or is_found(line) # check your condition in is_found
    return found

async def searchTask(self, ctx, *args):
    name = args[0].lower()
    surname = args[1].lower()
    await ctx.send("Searching data...")
    loop = asyncio.get_running_loop()
    with open(f"{CURRENT_DIR}/out.txt", "w") as fwrite:
        found = await loop.run_in_executor(None, search_files)
        # write something to fwrite
        # also do this in executor if it's a lot

   fwrite.close() # this is unnecessary if you as using 'with'
   if found:
       await ctx.send("Done! Here's the result:")
       await ctx.send(file=discord.File(f"{CURRENT_DIR}/out.txt"))
   else:
       await ctx.send("Can't find data")

Upvotes: 1

Related Questions