Threading: Threads steuern

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.
Antworten
kevelll
User
Beiträge: 10
Registriert: Donnerstag 9. Juli 2009, 11:04

Hallo liebe python-Gemeinde,

ich habe bis jetzt noch nie mit Threads gearbeitet und müsste folgendes Szenario abbilden/umsetzen:

Mein Code sichert mehrere VM's und nach jedem sichern einer VM wird diese gezippt. Bevor die nächste VM gesichert wird, muss erst das zippen beendet sein. Um den zeitlichen Verlauf zu reduzieren wollte ich nun mit Threads arbeiten. Wenn eine VM gesichert wurde, wird die VM ja gezippt und zeitgleich soll dann schon die nächste Sicherung der nächsten VM starten. Wichtig ist mir vor allem auch, dass nie zwei zippen-threads gleichzeitig laufen. Wenn noch ein zippen-prozess(thread) läuft, soll nicht der nächste schon anfangen sondern warten bis der eine fertig ist, auch wenn die nächste VM schon fertig gesichert wurde!

Ist solch ein Szenario überhaupt umsetzbar? Wenn ja, wie geht man am besten vor!?

Wurde mich über eine Antwort/Hilfestellung/Codeausschnitt sehr freuen.

Danke schon mal im voraus.
0x1cedd1ce
User
Beiträge: 31
Registriert: Sonntag 3. Oktober 2010, 12:21

Das ist recht einfach. Das zippen kannst du in ein Thread auslagern und dann mittels join() warten bis der Thread fertig ist bevor du den nächsten startest. Dafür gibt es das modul "threading". Kuck dir die Python-Dokumentation dazu an. Da steht alles drinn was du wissen musst, mit Code-beispielen
BlackJack

@kevelll: Müsste folgendes (ungetestet) nich eigentlich reichen?

Code: Alles auswählen

def save_vm(vm):
    # ...


def zip_vm(vm):
    # ...


def main():
    # vms = ...
    
    zip_thread = None
    
    for vm in vms:
        save_vm(vm)
        if zip_thread is not None:
            zip_thread.join()
        zip_thread = Thread(target=zip_vm, args=(vm,))
        zip_thread.start()
    
    if zip_thread is not None:
        zip_thread.join()
kevelll
User
Beiträge: 10
Registriert: Donnerstag 9. Juli 2009, 11:04

@0x1cedd1ce:

Okey die join-Methode habe ich verstanden.

Gehen wir nun mal von 2 VM's aus... dann würde folgendes ja zutreffen:


sichernThread(1) -> zippenThread(1) /sichernThread(1).join() -> sichernThread(2) -> zippenThread(2) /sichernThread(2).join()



sichernThread(1) ruft zippenThread(1) auf und wartet mit join() auf Beendigung des sichernThread(1). ZippenThread(1) ruft sofort wieder sichernThread(2) auf um die nächste VM zu sichern. sichernThread(2) ruft wiederum zippenThread(2) auf und wartet bis sichernThread(2) fertig ist (join). Aber wenn das zweite sichern schneller ist wie das erste sichern weil die VM kleiner ist, laufen ja 2 zippenThreads was nicht gewünscht ist. Wie sage ich nun zippenThread(2) er soll auf zippenThread(1) warten? Womöglich auch mit join() aber muss ich denn dann den sichernThread(1) dem sichernThread(2) übergeben? Alles verstanden!?

Das Script sichert zur Zeit 10 VM.

Vielleicht stehe ich ja auch nur auf'n Schlauch!?
kevelll
User
Beiträge: 10
Registriert: Donnerstag 9. Juli 2009, 11:04

BlackJack hat geschrieben:@kevelll: Müsste folgendes (ungetestet) nich eigentlich reichen?

Code: Alles auswählen

def save_vm(vm):
    # ...


def zip_vm(vm):
    # ...


def main():
    # vms = ...
    
    zip_thread = None
    
    for vm in vms:
        save_vm(vm)
        if zip_thread is not None:
            zip_thread.join()
        zip_thread = Thread(target=zip_vm, args=(vm,))
        zip_thread.start()
    
    if zip_thread is not None:
        zip_thread.join()

@BlackJack:
Wenn ich deinen Code richtig verstehe.... So ist ja eigentlich nur gewährleistet, dass keine zwei zippen-threads gleichzeitig laufen oder sehe ich das falsch? Weil wenn ein zip-thread gerade läuft wartet die ganze Anwendung bis der zip_thread fertig ist bevor überhaupt das nächste sichern beginnt! Dadurch verringert sich ja der zeitliche Verlauf nicht. Weil wenn gezippt wird soll schon die nächste VM gesichert werden. Damit zippen(vorherige VM) und sichern(nächste VM) gleichzeitig laufen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich würde einfach zwei Queues und zwei Worker-Threads verwenden. Jeweils für das Sichhern und für das Zippen:

Queue(Aufgaben)->sichern->Queue(Gesicherte)->zippen
Das Leben ist wie ein Tennisball.
kevelll
User
Beiträge: 10
Registriert: Donnerstag 9. Juli 2009, 11:04

@EyDu:

Super Idee. Das sollte eigentlich theoretisch die Lösung sein. Nach dieser Methode könnten alle VM's schon gesichert sein und z.B. 3 anstehen zip-prozesse stehen noch aus! Dann müsste ich am Ende meines Codes nur folgende ähnlichen Aufrufe machen:

Aufgaben.Queue.join()
Gesicherte.Queue.join()

richtig? Damit sich mein Script nicht beendet bevor alle Threads durch sind
BlackJack

@kevell: Da habe ich glaube ich Deine Anforderungen falsch verstanden. Meins stellt auch sicher dass sichern und zippen sich maximal um eine VM verschieben. Wenn das keine Anforderung ist, dann sind zwei Worker-Threads mit Queues in der Tat die einfachste Lösung. Beziehungsweise würde auch ein zusätzlicher Thread reichen, denn eine der beiden Tätigkeiten könnte man ja auch im Hauptthread erledigen. Das warten machst Du dann auf dem Thread und nicht auf der Queue.

Mein Code garantiert übrigens auch das keine zwei VMs gleichzeitig gesichert werden. Der zeitliche Ablauf verändert sich, weil ja sichern von VM und zippen von vorheriger Sicherung bei mir gleichzeitig laufen.
kevelll
User
Beiträge: 10
Registriert: Donnerstag 9. Juli 2009, 11:04

@BlackJack:
Okey vielleicht habe ich mich nicht genau genug ausgedrückt! Wichtig sind halt zwei Dinge. Bevor eine VM gezippt wird sollte sie zumindestens schon gesichert sein (Macht ja Sinn). Genauso das es nur maximal ein sichern und ein zippen -Thread zur gleichen Zeit geben soll. Da sonst die Schreibauslastung auf der Festplatte viel zu groß wird und ich denke das der Schreib-Lese-Kopf zu sehr am rotieren ist und dadurch das sichern und zippen mit meheren Threads eher von Nachteil sind! Deine Lösung ist ja auch so gut wie richtig...nur das die nächste VM-Sicherung erst beginnt wenn kein vorheriger zippen-thread mehr läuft! Aber dazu hast ja auch schon was geschrieben!

Ich werde heute versuchen eure Ideen und Vorschläge in Code umzusetzen und falls noch Fragen auftauchen werde ich mich melden.
Danke für eure Unterstützung!
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

@kevelll Das Betriebssystem hat einen Cache, nur bei einem flush ist garantiert dass die Daten sofort auf die Festplatte geschrieben werden. Deine Anwendung ist ja wahrscheinlich auch nicht die einzige die IO Operationen auf der Festplatte macht...
lunar

@DasIch: Es ist ganz unabhängig von irgendwelchen Puffern nicht sinnvoll, stark E/A-lastige Aufgaben zu parallelisieren. Die Festplatte ist immer der Flaschenhals, so dass eine Parallelisierung an dieser Stelle eher gegenteilige Effekte hat. Die Begrenzung auf einen einzigen Zip-Thread ist also in der Tat sinnvoll, Puffer hin oder her. Ganz abgesehen davon, dass die Puffergröße im Verhältnis zu den hier wohl anfallenden Datenmengen lächerlich gering ist, so dass der Puffer mit Ausnahme einiger Umordnungen einfach direkt ausgeschrieben wird. An der tatsächlich anfallenden E/A-Last ändert das nichts.
Antworten