Kapitel 20
Threads
566
Testen Sie das Programm! Klicken Sie mehrmals hintereinander auf die Schaltfläche LOS!.
Sie können beobachten, dass der Zähler sich nun sehr seltsam verhält. Die Zahl über dem
Knopf ändert sich häufiger als einmal pro Sekunde und manchmal springt sie auch auf
einen kleineren Wert zurück. Warum? Weil Sie mehrmals auf den Knopf gedrückt haben,
laufen nun mehrere Threads parallel (Methode
zaehlen()). Und zu einem bestimmten
Zeitpunkt ist jeder Prozess, der die Methode
zaehlen() ausführt, in einem anderen
Zustand. Während bei dem einen die lokale Variable
i den Wert 3 hat, hat sie bei einem
anderen Prozess den Wert
2 und bei noch einem anderen den Wert 1. Aber jeder Prozess
setzt die gemeinsame Variable
self.zahl auf seinen momentanen i-Wert.
20.2 Thread-Objekte erzeugen – die Klasse Thread
Soeben haben wir einen Thread generiert und ihm eine Funktion zugeordnet. Es ist aber
auch möglich, den Instanzen einer selbst definierten Klasse die Eigenschaften eines
Threads zukommen zu lassen. Dazu muss die Klasse als Ableitung (Unterklasse) der Klasse
Thread definiert werden. Die Klasse Thread befindet sich im Modul threading. Thread-
Objekte besitzen unter anderem die Methoden
start() und run(), die an die Unterklasse
vererbt werden. Die Methode
run() definiert die Aktivität des Threads und wird in der
Unterklasse überschrieben. Die Methode
start() wird aufgerufen, um den Thread zu star-
ten. Sie selbst ruft während ihrer Ausführung die interne Methode
self.run() auf.
Um Thread-Objekte zu erzeugen, gehen Sie am besten folgendermaßen vor:
Definieren Sie eine Unterklasse von Thread beginnend mit der Zeile
class MeinThread (Thread):.
import _thread
class Zaehler:
def __init__(self):
self.f = Tk()
self.zahl = StringVar()
Label(self.f, textvariable=self.zahl).pack()
Button(self.f,command=self.zaehlenThread,
t ext = ' Lo s ! '). p ack ( )
self.f.mainloop()
def zaehlenThread(self):
_thread.start_new_thread(self.zaehlen,())
def zaehlen(self):
for i in range(11):
self.zahl.set(str(i))
s lee p ( 1 )
z = Zaehler()
567
20.2
Thread-Objekte erzeugen – die Klasse Thread
In der Definition der __init__()-Methode muss zunächst ein Thread-Objekt instanzi-
iert werden. Das geschieht z.B. durch die Anweisung
Thread.__init__(self).
Überschreiben Sie die geerbte Methode run() und legen Sie dort die gewünschte Akti-
vität des Threads fest.
Erzeugen Sie ein oder mehrere Objekte Ihrer Thread-Unterklasse jeweils durch Aufruf
des Konstruktors, etwa in der Art
thread1 = MeinThread().
Starten Sie die Thread-Objekte mithilfe der (von Thread vererbten) start()-Methode,
z.B.
thread1.start(). Dies kann von außen (von einem anderen Objekt aus) zu einem
bestimmten erwünschten Zeitpunkt erfolgen. Wenn der Thread schon beim Start des
Programms laufen soll, kann
run() auch in der __init__()-Methode der Klasse gestar-
tet werden.
Das folgende Skript illustriert diese Technik. Es zeigt eine typische Anwendung von
Threads, nämlich eine Animation, in der sich mehrere visuelle Objekte nebeneinander
– quasi zeitgleich – bewegen. Dargestellt wird ein »Meteoritenhagel« im Weltraum. Man
sieht ständig Meteoriten mit unterschiedlichen Geschwindigkeiten von oben nach unten
fliegen (Abbildung 20.2).
Abb. 20.2: Eine Animation mit mehreren unabhängig voneinander sich bewegenden Objekten
Skript:
# meteore1.pyw
from tkinter import Tk, Canvas, PhotoImage
from threading import Thread
from time import sleep
from random import randint
class Weltraum(object):
def __init__(self):
s e l f .fe n ster = Tk( )
self.canvas = Canvas(self.fenster, width='10c',
h eig h t = '7c ' , bg = ' bla c k') #1
Kapitel 20
Threads
568
Erläuterung:
#1: Alle grafischen Objekte (die Meteore) werden auf einen Canvas gesetzt.
#2: Bilder von Meteoren (transparenter Hintergrund).
#3: Meteor-Objekte mit verschiedenen Bildern werden generiert. Das zweite Argument
id_nr ist die id des zugehörigen Bildes eines Gesteinsbrockens auf dem Canvas (siehe vorige
Programmzeile).
#4: Die Klasse Meteor wird als Unterklasse von Thread definiert.
self.canvas.pack()
m1 = PhotoImage(file='metgross.gif') #2
m2 = PhotoImage(file='metklein.gif')
for bild in [m1, m2, m2, m1, m2, m1, m2]:
id_nr = self.canvas.create_image(50, -50, image=bild)
Meteor(canvas=self.canvas, id_nr=id_nr) #3
self.fenster.mainloop()
cla s s Me t e o r(T h read ) : #4
def __init__(self, canvas=None, bild=None, id_nr=0):
Th r e ad. _ _ini t __( s e l f) #5
self.c = canvas
self.id = id_nr
se l f .__ n eust a rt( )
se l f .st a rt() #6
def _ _ne u star t ( sel f ) : #7
self.x = randint(0, 250)
self.y = - randint(30, 100)
self.vx = randint(-2, +2)
self.vy = randint (1, 3)
def run(self):
wh i l e Tr u e: #8
s l eep( 0 .05 ) #9
s e lf.x + = se l f.v x #10
self.y += self.vy
self.c.coords(self.id, self.x, self.y) #11
if self.y > 300:
s elf . __n e u sta r t () #12
Weltraum()

Get Python 3 - Lernen und professionell anwenden now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.