Threads oder Unterprogramme?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

Hallo.

Ich bin mir nicht ganz sicher wohin das Thema genau gehört. Hoffe mir kann jemand helfen.
Mein Problem bzw. Ausgangssituation:

Ich habe ein Script für den Streamlabs Chatbot geschrieben, dass den Chat überwacht und auf verschiedene Dinge reagiert.
Nun wollte ich den Bot um eine weitere Funktion erweitern, ende aber jedesmal in einer Endlosschleife.
Wenn im Chat für eine bestimmte Zeit keine Nachrichten mehr erscheinen, soll der Bot selbst etwas schreiben. Jedes Mal wenn eine Nachricht kommt, soll der Timer jedoch zurückgesetzt werden. Ich habe es soweit hinbekommen, dass jede Nachricht den Bot aushebelt, aber wenn die Zeit um ist, kommen für jede Nachricht im Chat eine Nachricht vom Bot. (Es sollte aber nur eine kommen.) Im Moment benutze ich threading.thread dafür. Dies scheint aber nicht die richtige Wahl zu sein, da man diese nicht "abbrechen" kann (Google).

Hat jemand eine Idee, wie ich ein "Hintergrundprogramm" laufen lasse, dass den Bot wie bei Thread nicht anhält, aber bei jeder Nachricht gestoppt und neu gestartet werden kann?

Ich hoffe man kann ungefähr verstehen was mein Ziel ist.

Außerdem: Ich möchte keine fertigen Scripts, da ich es sonst nicht lerne. Nur Ideen bzw. Schlagworte, mit denen ich das Ziel erreichen könnte.

Gruß Nemi
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nemi: Das sind zu wenige Informationen um wirklich etwas sagen zu können.

Es stimmt das man einen Thread nicht hart von ausserhalb des Threads abbrechen kann, aber man kann den Thread ja entweder von selbst beenden, oder ihn darüber informieren, das er sich selbst beenden soll. Auch bei Prozessen wäre es ein komischer Entwurf wenn man die einfach hart beendet, ohne mit ihnen zu kooperieren. Zumindest in diesem geschilderten Fall.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

@__blackjack__
Danke für die schnelle Reaktion.

Wie genau würde ich das machen mit dem Selbstabbruch des Threads? Eine globale Variable?

Im Moment macht mein Script folgendes:
1. Chat bekommt Nachricht.
2. Bot merkt sich die Zeit in einer Variable und startet Thread.
3. Thread beobachtet die Varibale und reagiert nach der eingestellten Zeit.
Falls nun aber eine Nachricht kommt bevor die zeit abgelaufen ist, wird die Variable ja überschrieben. D.h. Thread reagiert nicht. ABER sobald Thread reagiert, kommen alle Threads hintereinander, da ja bei jeder Nachricht ein Thread gestartet wurde.

Ich bräuchte also eine "Funktion" die den aktuellen Thread schließt, wenn die Zeitvariable überschrieben wurde.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nemi: Bloss keine globale Variable. Die sind ja so schon die Pest aber bei nebenläufiger Programmierung sind sie eine noch viel schlechtere Idee als sonst schon.

Es gibt im `threading`-Modul Datentypen um threadsicher auf Daten zuzugreifen. Zudem sind auch die Queue-Objekte aus dem `queue`-Modul threadsicher.

Bei Deinem jetzigen Vorgehen kann der Thread ja bevor er etwas macht, prüfen ob er denn überhaupt noch etwas machen muss. Andererseits macht es auch nicht so viel Sinn bei jeder Nachricht einen neuen Thread zu starten. Sinnvoll wäre es *einen* Thread zu starten, der immer mal wieder aufwacht und schaut ob er etwas machen muss. Den kann man über neu ankommende Nachrichten über eine Queue informieren, und wenn er eine gewisse Zeit keine neue Nachricht bekommt, kann er auf die letzte die angekommen ist, irgendwie reagieren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich kann mir schwer vorstellen, dass du nicht auch ohne Threads zum Ziel kommst. Stattdessen lieber Timer verwenden. Gibt es eine API-Dokumentation fuer dieses Chat-System?
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

@__blacjack__:

genau sowas suche ich xD

Habe auch grad versucht etwas in der Art einzupflegen.
1. Beim Starten des Bots wird die Funktion Background gestartet, die den Thread startet. Variable für Zeitfenster wird auch gesetzt.
2. Thread arbeitet mit while-Schleife, die die Zeit im Auge behält. Sobald die Zeit überschritten ist, verlässt der Thread die Schleife und startet Funktion Text sowie Background.
3. Funktion Text schreibt gewünschten Text.
ABER nun wieder Endlosschleife... ständig kommt der Text erneut, auch wenn ich (durch Chat-Nachricht) die Variable ändere.

Was genau mache ich falsch?

@__deets__:

Wie würde es mit Timer aussehen? Mein Problem ist halt, dass alle anderen Funktionen nebenbei weiterlaufen müssen.
Ja es gibt eine große Anleitung für den Bot aber wenig für die Python-Einbindung.
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Timer erlauben genau das. Statt einer Nachricht von einem Benutzer bekommst du eine Nachricht „timer fertig“.

Und der Vorteil des Timers ist: alles was du darin tust kannst du dann einfach als Nachricht verschicken etc.

wohingegen der Thread explizit mit der ereignisschleife verheiratet werden muss. Du kannst NICHT einfach aus dem Thread Nachrichten verschicken. Zumindest nicht, solange das explizit erwähnt & dokumentiert wurde. Darum die Frage danach, welche Python API du benutzt.
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

@__deets__:

Da bin ich jetzt völlig raus. Keine Ahnung welche API ich benutze Q_Q Habe mich aber zum Timer grad mal belesen:

Code: Alles auswählen

t = threading.Timer(10.0, TalkingBot(random.randint(1, 10)))
t.cancel()
t.start()
So steht es jetzt im Script. Aber anstatt der 10 Sekunden kommt der Text sofort?!
Das cancel soll den (eventuell schon bestehenden) Timer stoppen.
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na du redest doch mit dem Chat-System. Das ist eine API. Was fuer Kommandos setzt du da ab, wie wirst du von User-Nachrichten in Kenntnis gesetzt. Etc.

Und das ist nicht der Timer, den ich meinte. Das ist immer noch ein Thread, und hat die Probleme die ich ansprach.
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

achso, die api steckt schon in dem streamlabs chatbot drin, ich bekomme quasi fertige daten wie zum beispiel "data.isfromtwitch" oder "data.isfromchat" usw.

welchen timer meinst du dann? in der Hilfe von python ist nur dieser
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja. In Python ist nur der. Aber es geht um deinen Chatbot. In ganz Python steht nix von streamlabs. Das ist also irgendwie integriert. Als Paket, eingebetteter Interpreter oder was auch immer. Und DIESE INTEGRATION sollte so ein Feature haben.
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also ich habe mal kurz gegoogelt & das hier gefunden:

https://github.com/Bare7a/Streamlabs-Ch ... sSystem.py

Und so wie das aussieht gibt es da eine Tick-Methode, die regelmaessig aufgerufen wird. Und in der man solche Probleme wie deines loest.
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

die tick-methode hilft mir glaube ich nicht, da es ja das hauptscript unterbricht.
ich bekomm es einfach nicht hin.

Rein logisch passt ja alles:
Solange Nachrichten kommen wird immer wieder der Timer zurückgesetzt. Läuft der Timer ab, kommt der Text.
Aber das Script macht es nicht. Das hat auch nicht wirklich etwas mit der api zu tun. Da ich ja gerade nur versuche einen Timer (thread) zu starten und zu unterbrechen.
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Natuerlich hilft dir die Tick-Funktion. Jedes mal, wenn der Tick kommt, pruefst du, ob die Zeit verflossen ist. Wenn ja, dann tust du, was du tun willst. In der Execute-Funktion kannst du den Timer nach Bedarf wieder zurueck bzw weiter setzen. Und da wird auch nix unterbrochen. Die laufen unabhaengig voneinander. Execute wenn ein Ereignis reinkommt, und Tick, wenn ein Tick passiert (welche Einheit auch immer der hat).

Du DARFST aus deinem Thread ueberhaupt nichts machen. Wenn du aus dem Thread einfach Parent benutzt, da kann es sehr gut sein, dass der Bot abstuerzt.
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mal ein kleines Konzept (natuerlich nicht getestet, ich habe dieses Ding ja nicht):

Code: Alles auswählen

CHATTERBOX_TIMEOUT = 10 # nach 10 Sekunden Stille loslabern

chatterbox_timestamp = None

def Execute(data):
       global chatterbox_timestamp
       chatterbox_timestamp = time.time() + CHATTERBOX_TIMEOUT

def Tick():
       global chatterbox_timestamp
       if chatterbox_timestamp is not None and chatterbox_timestamp <= time.time():
              chatterbox_timestamp = None # nicht dauerlabern
              Parent.SendStreamMessage("laber was")
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

ok dann versteh ich python einfach falsch.

Kenne es nur von anderen Sprachen, dass man Funktionen immer aufrufen muss. Habe in dem Beispiel vorhin zb nicht gesehen, dass Tick aufgerufen wird un dachte deshalb es wird nicht benutzt.
Also läuft Tick dauerhaft mit?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nemi: Das hat nichts mit Python zu tun. Auch in Python muss man Funktionen aufrufen. Das scheint halt die API von diesem Chatbotdingens zu sein, dass das ein Modul haben will, und da nachschaut ob es eine Funktion mit dem Namen `Tick()` gibt, und die dann regelmässig aufruft. ”Normal” ist das für Python nicht. Die API ist so nicht wirklich schön.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nemi
User
Beiträge: 12
Registriert: Samstag 31. März 2018, 17:21

Ok ich habe jetzt __deets__ Beispiel eingebaut.
Entweder der Bot schreibt gar nichts oder Endlosschleife. (je nach Typ der Variable, int str)

Code: Alles auswählen

# Random thread to use
def Tick():
        if int(MsgTimeStamp) is not 0 and int(MsgTimeStamp) <= int(datetime.datetime.now().strftime("%y%m%d%H%M%S")):
                TalkingBot(random.randint(1, 10))
        return
bzw.

Code: Alles auswählen

# Random thread to use
def Tick():
        if MsgTimeStamp is not None and MsgTimeStamp <= int(datetime.datetime.now().strftime("%y%m%d%H%M%S")):
                TalkingBot(random.randint(1, 10))
        return
Es scheint ja irgendwas zu funktionieren, aber halt nicht so wie es soll xD
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum machst du diesen datetime-Kram? Das ist komplett Unfug. Warum hast du nicht benutzt, was ich geschrieben habe? Wenigstens zum ausprobieren? Und was tut TalkingBot?
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nemi hat geschrieben: Montag 24. September 2018, 16:37 Kenne es nur von anderen Sprachen, dass man Funktionen immer aufrufen muss. Habe in dem Beispiel vorhin zb nicht gesehen, dass Tick aufgerufen wird un dachte deshalb es wird nicht benutzt.
Also läuft Tick dauerhaft mit?
Wenn du das von anderen Sprachen so kennst, warum hat dich das bei Execute nicht auch gewundert? Das wird doch auch nur aufgerufen, wenn es was zu tun gibt, und laeuft nicht in einer Endlosschleife oder wird von dir selbst aufgerufen.
Antworten