Seite 1 von 1
Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 17:35
von atarax
Dieses Skript soll nacheinander zwei Stücke einer Audio-CD rippen. Bei einem einzelnen Stück funktioniert es auch, aber bei mehr als einem Stück werden die Unterprozesse schon gestartet, bevor der jeweils vorherige Prozess abgeschlossen ist, was dazu führt, dass der Lesekopf vom CD-Player natürlich immer hin- und her springt, da er versucht, mehrere Stücke gleichzeitig zu rippen. Wie kann ich das Skript so ändern, dass der nächste Prozess immer erst dann gestartet wird, wenn der vorherige abgeschlossen ist? Vielen Dank!
Code: Alles auswählen
def button2_clicked(self, widget):
for self.trackNumber in range(11,13): # main rip loop
self.ripTrack(self.trackNumber)
def ripTrack(self, n): # rip selected track to wav file
task = self.ripParanoia(n)
gobject.idle_add(task.next)
def ripParanoia(self, n):
cmd = ['cdparanoia', '-e', '-v', '-Z', '-B', '-d', '/dev/scd0', str(n), '/home/atarax/Desktop/Rip/ripper03/wav']
ripping = subprocess.Popen(cmd, stderr=subprocess.PIPE)
for line in ripping.stderr:
if "[read]" in line:
position = line[(line.rfind(" ") + 1):-1]
self.entry1.set_text(position)
yield True
yield False
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 17:50
von BlackJack
@atarax: Ich würde die Schaltfläche nach dem Klick deaktivieren und erst am Ende des Ripvorganges wieder aktivieren. Also wohl dann, wenn die ``for``-Schleife dort abgearbeitet ist.
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 18:25
von atarax
Ja, das ist schon realisiert. Aber das Problem ist ja nicht, dass während des Ripvorgangs erneut der Button geklickt wird, sondern, dass - wie üblich - vor dem Auslösen des Buttons in der Titelliste die gewünschten Titel ausgewählt werden und dann in der Schleife abgearbeitet werden. Wenn ich bspw. fünf Titel auswähle, werden eben auch fünf Prozesse gestartet, es darf aber immer nur einen geben. Irgendwo müsste eine Kontrolle eingebaut werden, ob der aktuelle Prozess noch läuft oder bereits beendet wurde, und dass erst dann die Schleife fortgesetzt wird. Mir ist aber nicht klar, wie das gemacht werden muss. Ich möchte hier nicht so gerne rumexperimentieren, weil ich fürchte, mir sonst mein Laufwerk zu beschädigen...
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 18:39
von Hyperion
Was macht denn folgende Zeile:
Das wird ja irgend ein Scheduler sein, der die Prozesse abarbeiten soll.
Das Problem dürfte sein, dass das Auslesen ja bereits gestartet wird, wenn Du ripParanoia() aufrufst!
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 18:50
von atarax
@Hyperion:
Die Zeile kommt von hier:
How do I update a progress bar and do some work at the same time
Diese Funktion wird hier beschrieben:
gobject.idle_add
Ich hab das einfach in mein Skript eingebaut, aber was da genau passiert, weiß ich auch nicht.
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 18:57
von Hyperion
Dann liegt das Problem doch auf der Hand: Du musst einfach unterbinden, dass mehrere Tasks parallel gestartet werden können. Wie Du das genau realisieren kannst, weiß ich nicht. Das beste wäre, wenn Du hier
irgend wie an einen Rückgabewert kämest oder irgend eine Möglichkeit hast damit festzustellen, dass das "False" "geyielded" wurde.
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:11
von atarax
Das sehe ich auch so. Ich verstehe den Ablauf momentan so, dass der nächste Prozess erst dann gestartet wird (gobject.idle_add(task.next)), wenn der Rückgabewert (yield) von ripParanoia() False ist, denn bis dahin ist der Prozess ja eben gerade nicht idle. Aber genau das passiert eben nicht.
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:17
von Hyperion
Nein, nein, das klappt schon so! Das Problem liegt quasi hier:
Code: Alles auswählen
def ripTrack(self, n):
# Dieser Aufruf passiert doch quasi mehrfach direkt hintereinander
task = self.ripParanoia(n)
# hier ist es schon zu spät
gobject.idle_add(task.next)
Genau da liegt das Problem. Sobald Du die Funktion ripParanoia aufrufst, stößt Du doch schon einen neuen Ripping-Process extern an. Das darf erst dann passieren, wenn dieser gobject-Scheduler fertig ist mit dem letzten.
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:20
von atarax
Also ich vermute, dass das Problem eher in der for-Schleife zu suchen ist, die ja im Moment brav durchlaufen wird, ohne eben zu prüfen, wie viele Prozesse schon laufen. Vielleicht gibt es eine Möglichkeit, den Inkrement der Schleife an eine Bedingung zu koppeln, die genau diese Prüfung vornimmt...
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:27
von Hyperion
atarax hat geschrieben:Also ich vermute, dass das Problem eher in der for-Schleife zu suchen ist, die ja im Moment brav durchlaufen wird, ohne eben zu prüfen, wie viele Prozesse schon laufen. Vielleicht gibt es eine Möglichkeit, den Inkrement der Schleife an eine Bedingung zu koppeln, die genau diese Prüfung vornimmt...
Ähem... schau Dir doch mal die for-Schleife an... da passiert ja nix, als dass die gerade von mir kommentierte ripTrack aufgerufen wird! Letztlich kann ich bis runter gehen bis in die ripParanoia(), da dort ja per subprocess der Ripper gecallt wird. Ehrlich gesagt dachte ich, das wäre jetzt klar gewesen

Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:31
von atarax
Na das Problem wird so langsam in der Tat immer klarer. Nur eine Lösung erscheint mir noch nicht. Vielleicht statt einer for-Schleife eine while-Schleife mit einer zusätzlichen Bedingung? Wobei mir noch nicht klar ist, wie diese Bedingung zu formulieren ist...
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:41
von Hyperion
Das Problem ist klar:
Noch mal langsam: Du hast eine for-Schleife, in der Du
unmittelbar nacheinander über eine Funktion hinweg den Subprozess anstößt. Ob Du da etwas in diese gobject Prozess-Queue reinpackst oder nicht, spielt dabei
keine Rolle.
Meine quick and dirty Idee: Um zu verhindern, dass die ripParanoia()-Funktion vor dem Hinzuügen in die Queue aufgerufen wird, übergebe doch direkt den Callback und nicht schon den Iterator:
Code: Alles auswählen
def button2_clicked(self, widget):
# wieso iterierst Du eigentlich über eine ObjektVariable?
for self.trackNumber in range(11,13):
# einfach nur den Cllback übergeben und dann die tracknummer als weiteren Parameter.
gobject.idle_add(self.ripParanoia, self.trackNumber)
Alternativ könntest Du auch versuchen, in der ripParanoia() vor dem Aufruf des Subprozesses ein "yield True" zu setzen. Aber das würde mir persönlich zu dirty sein!
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:51
von atarax
Na, ich hab das mal probiert. Außer dass ich eine 100%ige Prozessorlast bekomme (bis ich das Programm selbst beende), passiert nichts. Keine Tracks werden gerippt und self.entry1.set_text(position) funktioniert auch nicht... Zu dirty, wie es scheint

Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 19:55
von Hyperion
Sei doch mal präziser! Ich habe doch zwei Vorschläge gemacht! Welchen hast Du denn probiert?
Re: Wie Unterprozesse nacheinander starten?
Verfasst: Freitag 29. Oktober 2010, 20:05
von atarax
Sorry, meine Antwort bezog sich auf deinen ersten Vorschlag. Ich habe jetzt noch den anderen probiert, aber da rumpelt es wieder in meinem CD-Laufwerk...