0

I'm trying to build a discord bot where there's a delay in between asking for an upgrade and the upgrade being received. With 2 upgrade slots, you should be able to fill both at the same time. However, it's not letting me add 2 delays at the same time (2 time.sleep()). On discord when I put the command for both functions one after the other, it takes 10 seconds to execute the first one and then another 10 seconds to execute the second, when I would preferably want it to take both simultaneously, meaning overall 10 seconds instead of 20. My code is below. Any ideas?

if message.content.startswith('fd!upgradefw'):
  if message.author.id == [id]:
    if Slots > 0:
      await message.channel.send("Upgrading!")
      Slots = Slots - 1
      time.sleep(10)
      await message.channel.send("Upgrade Complete!")
      FWForli = FWForli+1
if message.content.startswith('fd!upgraderw'):
  if message.author.id == [id]:
    if Slots > 0:
      await message.channel.send("Upgrading!")
      Slots = Slots - 1
      time.sleep(10)
      await message.channel.send("Upgrade Complete!")
      RWForli = RWForli+1
Versigot
  • 3
  • 1
  • I'm not familiar with discord.py, but I assume your problem would be solved by packaging both statements into functions and using the [threading](https://docs.python.org/3/library/threading.html) module...? Reply to the comment if you need elaboration, I'll post an answer. – Codeman Feb 03 '22 at 02:58
  • I read up a little on threading, but I'm not 100% sure how it would work. It's definitely the way to go, but how would I make it so that there's a 10 second delay between it all happening? This is a step in the right direction but I don't fully understand – Versigot Feb 03 '22 at 03:17

1 Answers1

0

As mentioned in my comment, I'm not familiar with discord.py, and all I'm seeing from your problem is this: "I want to have two of my if statements execute at the same time". This means the 10 second delays would overlap, so it would only take 10 seconds in total.

Here's a relevant example:

from threading import Thread
from time import sleep

def check_delay_special(arg):
    print("starting special!")
    if arg == 'special':
        sleep(10)
        print("10 seconds have passed (special)!\n")

def check_delay_normal(arg):
    print("starting normal!")
    if arg == 'normal':
        sleep(10)
        print("10 seconds have passed (normal)!\n")

norm = Thread(target=check_delay_normal, args=('normal',))   # The args param is for passing args
spec = Thread(target=check_delay_special, args=('special',))
norm.start()   # start the threads
spec.start()
norm.join()    # block the calling thread (the main program) till these threads finish
spec.join()



# Output:
starting normal!    # Both of these execute at roughly the same instant
starting special!
    # there's a 10 second delay between these two
10 seconds have passed (special)!   # Again, same instant execution
10 seconds have passed (normal)!

If you change the args to not satisfy the if function, the thread would terminate immediately. I recommend experimenting a bit to see how it works!

Of course, this is based on the assumption that you can pass whatever your if statements are checking to a function. If this is not what you were looking for or it does not work with discord, please leave a comment for this answer.

Here are similar/helpful questions on stackoverflow:

Multiprocessing vs Threading Python, How to do parallel programming in Python?, Parallel Programming - Python, How can I use threading in Python?, Python: Understanding Threading Module

Note that many of them use the multiprocessing module. Also, Python doesn't allow you to actually execute code in parallel with threading, but it should work well enough for your example.

Codeman
  • 477
  • 3
  • 13
  • Ok, this sounds great! Thanks so much for the advice mr codeman! – Versigot Feb 03 '22 at 04:19
  • @Versigot No problem. Consider marking the question as accepted if it helped you. – Codeman Feb 03 '22 at 04:24
  • So I went to actually code the program, and it all seemed to be going smoothly before it failed to compile and, after a bit of digging, it showed that I can't use a coroutine in a function (in the code you showed, print wouldn't work. You would have to write 'await message.channel.send("abcdefgh")'. Would a Task also work in this scenario? Or no? – Versigot Feb 03 '22 at 14:18
  • I've never tried using `asyncio`, so I can't say for sure. Does the `await message.channel.send('...')` work if you switch out `threading` for `multiprocessing`? Try a minimal example: If it does, I'll update my answer, and if it doesn't I'll try looking at what parallel-programming modules work with asyncio. – Codeman Feb 03 '22 at 14:50
  • @Versigot would this work? It uses nothing but the `asyncio` module: [link here](https://hackernoon.com/threaded-asynchronous-magic-and-how-to-wield-it-bba9ed602c32). Basically, replace `sleep` with `await asyncio.sleep` and `def` with `async def`, then call with this mess: `loop.run_until_complete(asyncio.gather(*asyncio.ensure_future(check_delay_normal('normal')), asyncio.ensure_future(check_delay_special('special'))]))`. – Codeman Feb 03 '22 at 15:02
  • It worked! I used asyncio.ensure_future to get it to eventually run, and it still took a few hours of fixes and reading random reddit and stackoverflow questions to get there, but my bot works! Thank you so much for your help mr codeman! – Versigot Feb 04 '22 at 02:44