PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Python: Class-Member haben in Main-Thread und Background-Thread andere Werte


Matti
2025-04-18, 12:51:47
In folgendem Python-Code wird die Member-Funktion "analyze" parallel ausgeführt und das Ergebnis in self.findings gespeichert. Leider bekomme ich in Main-Thread eine Exception, dass "self" kein Attribut "findings" hat.

class JiraAnalyze:
def __init__(self, pipeline, jira, issue):
doSomething()

def analyze(self):
self.findings = something()

def present(self):
print(self.findings)

def processTickets(pipeline, jira, tickets):
print("Parallel analysis of",len(tickets),"tickets")
analyzers = []
threads = []
for ticket in tickets:
a = JiraAnalyze(pipeline,jira,ticket,True)
analyzers.append(a)
t = Process(target=JiraAnalyze.analyze, args=(a,))
t.start()
threads.append(t)

print("Waiting for background threads to finish")
for t in threads:
t.join()

print("Background threads have finished")
for a in analyzers:
a.present()

Wie kann man das Problem lösen?

Asaraki
2025-04-18, 13:24:21
In dem du beim Aufruf ein Objekt mitgibst, das findings hat ^^

Ist ohne den ganzen Code jetzt müssig zu erklären, aber so dumm es klingt : die Fehlermeldung ist akkurat :D

Gast
2025-04-18, 13:25:57
Chathgbt

Das Verhalten, dass class member unterschiedliche Werte im Hauptprozess und im Hintergrundprozess (Thread) haben, liegt in deinem Fall nicht an Threads, sondern an der Verwendung von multiprocessing.Process.

Hauptursache: multiprocessing.Process erstellt einen neuen Prozess

In Python bedeutet Process aus dem multiprocessing-Modul:

Jeder neue Process ist ein komplett eigener Speicherbereich.

Änderungen an Objekten in einem Kindprozess sind nicht sichtbar im Hauptprozess.


Was passiert genau in deinem Code?

for ticket in tickets:
a = JiraAnalyze(pipeline, jira, ticket, True)
analyzers.append(a)
t = Process(target=JiraAnalyze.analyze, args=(a,))
t.start()
threads.append(t)

Du erzeugst ein Objekt a im Hauptprozess.

Du startest einen neuen Prozess, der JiraAnalyze.analyze(a) aufruft.

Dieser neue Prozess bekommt eine Kopie von a (per Pickle serialisiert).

In analyze() wird self.findings gesetzt, aber nur im Kindprozess.

Nach join() versuchst du im Hauptprozess a.present() aufzurufen.

Da self.findings dort nie gesetzt wurde, kommt AttributeError oder None.


Lösungsmöglichkeiten

1. Verwende threading.Thread, wenn du gemeinsamen Speicher brauchst

from threading import Thread

t = Thread(target=JiraAnalyze.analyze, args=(a,))

Damit bleiben a.findings im Hauptthread und im Thread gleich, weil Speicher geteilt ist.

2. Verwende multiprocessing.Queue, Manager, oder Pipe, um Daten auszutauschen

from multiprocessing import Process, Manager

def worker(a, findings_dict, index):
a.analyze()
findings_dict[index] = a.findings

with Manager() as manager:
findings = manager.dict()
threads = []
for i, ticket in enumerate(tickets):
a = JiraAnalyze(pipeline, jira, ticket)
analyzers.append(a)
t = Process(target=worker, args=(a, findings, i))
t.start()
threads.append(t)
for t in threads:
t.join()
for i, a in enumerate(analyzers):
a.findings = findings[i]
a.present()

Möchtest du Threads oder Prozesse verwenden? Dann kann ich dir das entsprechende Setup bauen.

Matti
2025-04-18, 20:59:05
Threads nutzen leider nichts, weil mehrere Threads in Python auch nur 1 CPU-Kern benutzen. Habe mich für ChatGPT's Lösung mit multiprocessing.Manager entschieden.