0

I am trying to use asyncio together with threading for a Discord Bot. I've found this script which I changed to my needs:

import time
import threading as th
import asyncio
import discord

class discordvars(object):
    client=discord.Client()
    TOKEN=('---')
    running_discordthread=False

    discordloop = asyncio.get_event_loop()
    discordloop.create_task(client.start(TOKEN))
    discordthread=th.Thread(target=discordloop.run_forever)

def start():
    if discordvars.running_discordthread==False:
        discordvars.discordthread.start()
        print("Discord-Client started...")
        discordvars.running_discordthread=True
    else:
        print("Discord-CLient allready running...")
    time.sleep(2)
    
def stop():
    if discordvars.running_discordthread==True:
        discordvars.discordloop.call_soon_threadsafe(discordvars.discordloop.stop())
        print("Requestet Discord-Client stop!")
        discordvars.discordthread.join()
        print(discordvars.discordthread.isAlive())
        time.sleep(1)
        print("Discord-Client stopped...")
        discordvars.running_discordthread=False
    else:
        print("Discord-Client not running...")
    time.sleep(2)


@discordvars.client.event
async def on_message(message):
    if message.content.startswith('!test'):
        embed = discord.Embed(title="test", color=0x0071ce, description="test")
        await message.channel.send(embed=embed)

Starting the Script with the start() function works great. Also stopping with the stop() function works somehow. If I call the stop() function it prints: "False" so I am thinking that the thread was stopped. But if I then call the start() function I will get an error:

RuntimeError: threads can only be started once

This script is part of a big project so I am calling the functions from another script. But I think that shouldn't be the problem.

What is the problem? Thanks in advance.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Paul
  • 177
  • 2
  • 9

1 Answers1

0

You cannot re-start the existing thread, but you can start a new thread that runs the event loop. You can achieve that by moving the assignment to discordthread to the start function.

And your call to call_soon_threadsafe is wrong. You need to pass discordloop.stop to it, without parentheses. That refers to the actual function without calling it right away, and allows the loop thread to call it, which was intended:

discordloop.call_soon_threadsafe(discordloop.stop)

Finally, your init function is missing a global declaration for the variables you assign that are intended as globals.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • I think my Question wasn't formulated well. Sorry. So I edited my Question and now it should be a little bit clearer. I tried putting discord thread inside of start/stop but I am still getting the error. – Paul Oct 22 '20 at 07:27
  • @Paul Sorry, but now it's even less clear than before. You are accessing attributes of `init` which the script you've shown never sets. Also you mention what you tried, but you didn't show that code - how can we tell what's wrong? You need to show the exact script you are running, just removing the discord event handling for brevity. – user4815162342 Oct 22 '20 at 07:34
  • I am really sorry. My native language isn't English. I tried my best to explain it well. The code wich is postet above is the exact code I am running. – Paul Oct 22 '20 at 08:51
  • @Paul It cannot be exact code because there is no top-level code that will start asyncio or discord or just invoke `discordfunction()` and others. Also, the syntax is incorrect due to inconsistent indentation, Python would never accept it. If you want help, please post your actual code and take care to copy it correctly. – user4815162342 Oct 22 '20 at 08:57
  • It seems like the last time I edited the code it somehow didn't change. So now it's the 100% exact code I am using. I only removed the Token. I can't post my main script here because it's way too long but the only thing what I am doing in the main script is importing the `start()` and `stop()` functions and then executing them. – Paul Oct 22 '20 at 09:19
  • @Paul Why do you use threads in the first place? Why don't you just run discord in the main thread the way it is designed to be used? – user4815162342 Oct 22 '20 at 09:24
  • The problem is that the main script starts about 10 other scripts simultaneously and I couldn’t figure out a way how to run these scripts and the discord script at the same time. Is there a better way? – Paul Oct 22 '20 at 09:38
  • @Paul Yes, you can use asyncio to start and monitor the subprocesses, see `asyncio.create_subprocess_exec`. You don't need threads at all. If you have an issue, you should post a new question that describes your _actual_ problem rather than the problem you encountered while trying to solve it in a specific way. (See [xy problem](http://xyproblem.info/).) – user4815162342 Oct 22 '20 at 09:50