Nebenläufig
Neben den Python-Mechanismen zur nebenläufigen Programmierung bietet das Qt-Framework im Wesentlichen drei Möglichkeiten, um Programmcode nebenläufig auszuführen:
- »
QtCore.QThread« stellt die Basisklasse für plattformunabhängige Threads dar. Ihre Schnittstelle ähnelt der in Pythons Threading-Bibliothek enthaltenen Thread-Klasse. Die Funktionalität des Thread wird entsprechend in der »run()« -Methode implementiert. - »
QtCore.QObject.moveToThread()« ändert die Thread-Affinität eines Objekts und seiner Kinder nach deren Erstellung. - »
QtCore.QtConcurrent« soll eine High-Level-Programmierschnittstelle für Nebenläufigkeit bei Py Side bieten, ist aber noch Zukunftsmusik.
Listing 6 haucht dem Währungsumrechner Leben ein und implementiert die Umrechnung mittels der XML-RPC-Schnittstelle in einem eigenen Thread. Der Zugriff auf die XML-RPC Schnittstelle erfolgt mit Hilfe des mit Python mitgelieferten Moduls »xmlrpclib«
. Ein dazu notwendiges Proxy-Objekt legt Zeile 8 mit der entsprechenden URL an.
Listing 6
app_qthread.py (gekürzt)
01 [...]
02 class CCurrencyThread(QtCore.QThread):
03
04 calculated = QtCore.Signal(str)
05
06 def __init__(self):
07 super(CCurrencyThread, self).__init__()
08 self.mProxy = xmlrpclib.ServerProxy("http://foxrate.org/rpc/")
09 [...]
10
11 def setArgs(self, pCurSrc, pCurDst, pVal):
12 [...]
13
14 def run(self):
15 lResult = self.mProxy.foxrate.currencyConvert(\
16 self.mCurSrc, \
17 self.mCurDst, \
18 self.mVal)
19 if lResult['message'] != '"N/A"':
20 self.calculated.emit(str(lResult['amount']))
21 else:
22 self.calculated.emit('')
23
24
25 # Create a class for our main window
26 class Gui_Qt(QtGui.QMainWindow):
27
28 def __init__(self, parent=None):
29 super(Gui_Qt, self).__init__(parent)
30
31 self.mThread = CCurrencyThread()
32 self.mMutex = QtCore.QMutex()
33
34 [...]
35 self.mThread.calculated.connect(self.on_thread_calculated,
36 QtCore.Qt.QueuedConnection)
37
38 def on_actionExit_triggered(self):
39 while self.mThread.isRunning() == True:
40 QtCore.QThread.msleep(100)
41 self.close()
42
43 def on_processButton_clicked(self):
44 if self.mMutex.tryLock() == True:
45 self.mThread.setArgs(
46 self.customwidget.sourceCurrency.text(),
47 self.customwidget.destinationCurrency.text(),
48 int(self.customwidget.value.text()))
49 self.mThread.start()
50
51 def on_thread_calculated(self, pAmount):
52 if pAmount == '':
53 self.customwidget.result.setText("")
54 self.customwidget.status.setText("<html><font \
55 color=\"red\">Fehler!</font></html>")
56 else:
57 self.customwidget.result.setText(str(pAmount))
58 self.customwidget.status.setText("OK")
59 self.mMutex.unlock()
60 [...]
Die Zeilen 35 und 36 verbinden die Signale der grafischen Elemente mit den zugehörigen Slots. Hierbei kommt der Parameter »Qt.QueuedConnection«
zum Einsatz, um die Thread-Sicherheit zu gewährleisten. Klickt der Benutzer auf den Knopf »Berechnen«
, versucht das Programm ein »QMutex«
-Objekt zu sperren. Diese Objekte dienen zur Synchronisation mehrerer Threads. Ist bereits eine Berechnung in Gange, schlägt die Bedingung in Zeile 44 fehl. Ist das Mutex frei, startet der Thread nach seiner Initialisierung (Zeilen 45 bis 48) in Zeile 49.
Die eigentliche Umrechnung findet per XML-RPC-Proxy in den Zeilen 15 bis 18 statt. Der Code macht das Ergebnis bekannt, indem er ein »calculated«
-Signal aussendet (Zeilen 20 und 22). Dies ist als Klassenmethode in Zeile 4 deklariert. Auf Seiten der grafischen Oberfläche erfolgt die Auswertung des Ergebnisses im verbundenen Slot »on_thread_calculated()«
(Zeilen 51 bis 59). An dieser Stelle erfolgt auch die Freigabe des Mutex (Zeile 59), sodass der Anwender eine neue Berechnung starten kann.
In Qt ist der zweite Ansatz, um Programmcode mit der Methode »QObject.moveToThread()«
[12] in einen anderen Ausführungskontext zu verschieben, plattformübergreifend einheitlich implementiert. Listing 7 zeigt das Prinzip: Nachdem das Objekt und der Thread erzeugt sind, verschiebt das Programm die Thread-Affinität des Objekts. Methodenaufrufe des Objekts erfolgen nun im zugewiesenen Thread.
Listing 7
moveToThread()
01 lObject = QtCore.QObject() 02 lThread = QtCore.QThread() 03 lObject.moveToThread(lThread) 04 lThread.start() 05 lObject.exampleMethod()
Mit »moveToThread()«
ergibt sich aber das Problem, dass sich Signale in einer Warteschlange sammeln. Es gibt dann zwar keine Schwierigkeiten mit der Thread-Sicherheit, sendet der Benutzer aber das Signal zum Starten einer so verschobenen Methode mehrmals rasch hintereinander, wird die unter Umständen zeitaufwändige Methode auch mehrmals hintereinander ausgeführt.
Bei komplexen Berechnungen muss sich der Entwickler aber ohnehin Gedanken machen, wie er die grafische Oberfläche ansprechbar hält. Der Artikel "Keeping the GUI responsive" von Witold Wysota [13] beschreibt gängige Strategien.
Gutes GUI-Gefühl
Die Verwendung von Threads ist in Python aufgrund des Global Interpreter Lock (GIL) generell problematisch. Die Abhängigkeiten bei der Ausführung von Code in mehreren Threads sind für den Skriptprogrammierer oft nicht erkennbar. Soll komplexerer Programmcode daher plattformübergreifend parallel laufen, hat sich der Einsatz des im Lieferumfang von Python enthaltenen Moduls »multiprocessing«
am besten bewährt. Es ist zwar nur über Umwege möglich, aus gestarteten Prozessen auf Elemente der grafischen Benutzeroberfläche zuzugreifen, meist ist das aber auch unerwünscht oder widerspricht den Vorgaben der Software-Architektur.
Online PLUS
Ein weiterführender Artikel unter der URL [http://www.linux-magazin.de/plus/2011/11] zeigt Ihnen, wie Sie Ressourcendateien sowie Qt Quick und QML für GUI-Programme verwenden.
Das Beispielprogramm läuft bei installiertem Python und Py Side auf Linux (Abbildung 2), Windows (Abbildung 3) und Mac OS X. Die Installation von Py Side auf dem Maemo-Gerät N 900 dagegen erwies sich im Test als relativ schwierig. Eine Alternative besteht darin, die Anwendung mit dem Qt Simulator auszuprobieren [14]. Ein Aufruf des Programms startet die Applikation in der gewünschten Umgebung. Abbildung 4 zeigt die Konfiguration für das N 900.
Diesen Artikel als PDF kaufen
Express-Kauf als PDF
Umfang: 6 Heftseiten
Preis € 0,99
(inkl. 19% MwSt.)
Als digitales Abo
Weitere Produkte im Medialinx Shop »
Versandartikel
Onlineartikel
Alle Rezensionen aus dem Linux-Magazin
- Buecher/07 Bücher über 3-D-Programmierung sowie die Sprache Dart
- Buecher/06 Bücher über Map-Reduce und über die Sprache Erlang
- Buecher/05 Bücher über Scala und über Suchmaschinen-Optimierung
- Buecher/04 Bücher über Metasploit sowie über Erlang/OTP
- Buecher/03 Bücher über die LPI-Level-2-Zertifizierung
- Buecher/02 Bücher über Node.js und über nebenläufige Programmierung
- Buecher/01 Bücher über Linux-HA sowie über PHP-Webprogrammierung
- Buecher/12 Bücher über HTML-5-Apps sowie Computer Vision mit Python
- Buecher/11 Bücher über Statistik sowie über C++-Metaprogrammierung
- Buecher/10 Bücher zu PHP-Webbots sowie zur Emacs-Programmierung
Insecurity Bulletin
Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...





