Python - Multithread-Programmierung
Das Ausführen mehrerer Threads ähnelt dem gleichzeitigen Ausführen mehrerer verschiedener Programme, bietet jedoch die folgenden Vorteile:
Mehrere Threads innerhalb eines Prozesses teilen sich den gleichen Datenraum mit dem Hauptthread und können daher einfacher Informationen austauschen oder miteinander kommunizieren, als wenn es sich um separate Prozesse handeln würde.
Threads werden manchmal als leichte Prozesse bezeichnet und erfordern nicht viel Speicheraufwand. Sie sind billiger als Prozesse.
Ein Thread hat einen Anfang, eine Ausführungssequenz und eine Schlussfolgerung. Es verfügt über einen Anweisungszeiger, der verfolgt, wo in seinem Kontext es gerade ausgeführt wird.
Es kann vorbelegt (unterbrochen) werden
Es kann vorübergehend angehalten werden (auch als Ruhezustand bezeichnet), während andere Threads ausgeführt werden - dies wird als Nachgeben bezeichnet.
Einen neuen Thread starten
Um einen anderen Thread zu erzeugen, müssen Sie die folgende im Thread- Modul verfügbare Methode aufrufen :
thread.start_new_thread ( function, args[, kwargs] )
Dieser Methodenaufruf ermöglicht eine schnelle und effiziente Möglichkeit, neue Threads unter Linux und Windows zu erstellen.
Der Methodenaufruf wird sofort zurückgegeben und der untergeordnete Thread startet und ruft die Funktion mit der übergebenen Liste von Argumenten auf . Wenn die Funktion zurückkehrt, wird der Thread beendet.
Hier ist args ein Tupel von Argumenten; Verwenden Sie ein leeres Tupel, um die Funktion aufzurufen, ohne Argumente zu übergeben. kwargs ist ein optionales Wörterbuch mit Schlüsselwortargumenten.
Beispiel
#!/usr/bin/python
import thread
import time
# Define a function for the thread
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print "%s: %s" % ( threadName, time.ctime(time.time()) )
# Create two threads as follows
try:
thread.start_new_thread( print_time, ("Thread-1", 2, ) )
thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print "Error: unable to start thread"
while 1:
pass
Wenn der obige Code ausgeführt wird, wird das folgende Ergebnis erzeugt:
Thread-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009
Es ist zwar sehr effektiv für Low-Level-Threading, aber das Thread- Modul ist im Vergleich zum neueren Threading-Modul sehr begrenzt.
Das Threading- Modul
Das neuere Threading-Modul in Python 2.4 bietet eine viel leistungsfähigere Unterstützung auf hoher Ebene für Threads als das im vorherigen Abschnitt beschriebene Thread-Modul.
Das Einfädeln Modul aussetzt alle Methoden des Fadenmoduls und bietet einige zusätzliche Methoden -
threading.activeCount() - Gibt die Anzahl der aktiven Thread-Objekte zurück.
threading.currentThread() - Gibt die Anzahl der Thread-Objekte im Thread-Steuerelement des Aufrufers zurück.
threading.enumerate() - Gibt eine Liste aller aktuell aktiven Thread-Objekte zurück.
Zusätzlich zu den Methoden verfügt das Threading-Modul über die Thread- Klasse, die das Threading implementiert. Die von der Thread- Klasse bereitgestellten Methoden lauten wie folgt:
run() - Die run () -Methode ist der Einstiegspunkt für einen Thread.
start() - Die Methode start () startet einen Thread durch Aufrufen der Methode run.
join([time]) - Join () wartet auf das Beenden von Threads.
isAlive() - Die Methode isAlive () prüft, ob noch ein Thread ausgeführt wird.
getName() - Die Methode getName () gibt den Namen eines Threads zurück.
setName() - Die Methode setName () legt den Namen eines Threads fest.
Thread mit Threading- Modul erstellen
Um einen neuen Thread mit dem Threading-Modul zu implementieren, müssen Sie Folgendes tun:
Definieren Sie eine neue Unterklasse der Thread- Klasse.
Überschreiben der __init __ (self [, args]) Verfahren zusätzliche Argumente hinzuzufügen.
Überschreiben Sie dann die Methode run (self [, args]), um zu implementieren, was der Thread beim Starten tun soll.
Nachdem Sie die neue Thread- Unterklasse erstellt haben, können Sie eine Instanz davon erstellen und dann einen neuen Thread starten , indem Sie start () aufrufen , das wiederum die Methode run () aufruft .
Beispiel
#!/usr/bin/python
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
print_time(self.name, 5, self.counter)
print "Exiting " + self.name
def print_time(threadName, counter, delay):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
print "Exiting Main Thread"
Wenn der obige Code ausgeführt wird, wird das folgende Ergebnis erzeugt:
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2
Threads synchronisieren
Das mit Python gelieferte Threading-Modul enthält einen einfach zu implementierenden Sperrmechanismus, mit dem Sie Threads synchronisieren können. Eine neue Sperre wird durch Aufrufen der Lock () -Methode erstellt, die die neue Sperre zurückgibt.
Die Erfassungsmethode (Blockierungsmethode) des neuen Sperrobjekts wird verwendet, um zu erzwingen, dass Threads synchron ausgeführt werden. Mit dem optionalen Blockierungsparameter können Sie steuern, ob der Thread darauf wartet, die Sperre zu erhalten.
Wenn das Blockieren auf 0 gesetzt ist, kehrt der Thread sofort mit einem 0-Wert zurück, wenn die Sperre nicht erfasst werden kann, und mit einer 1, wenn die Sperre erworben wurde. Wenn die Blockierung auf 1 gesetzt ist, blockiert der Thread und wartet, bis die Sperre aufgehoben wird.
Die release () -Methode des neuen Sperrobjekts wird verwendet, um die Sperre aufzuheben, wenn sie nicht mehr benötigt wird.
Beispiel
#!/usr/bin/python
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
# Get lock to synchronize threads
threadLock.acquire()
print_time(self.name, self.counter, 3)
# Free lock to release next thread
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
# Add threads to thread list
threads.append(thread1)
threads.append(thread2)
# Wait for all threads to complete
for t in threads:
t.join()
print "Exiting Main Thread"
Wenn der obige Code ausgeführt wird, wird das folgende Ergebnis erzeugt:
Starting Thread-1
Starting Thread-2
Thread-1: Thu Mar 21 09:11:28 2013
Thread-1: Thu Mar 21 09:11:29 2013
Thread-1: Thu Mar 21 09:11:30 2013
Thread-2: Thu Mar 21 09:11:32 2013
Thread-2: Thu Mar 21 09:11:34 2013
Thread-2: Thu Mar 21 09:11:36 2013
Exiting Main Thread
Multithread-Prioritätswarteschlange
Mit dem Warteschlangenmodul können Sie ein neues Warteschlangenobjekt erstellen, das eine bestimmte Anzahl von Elementen enthalten kann. Es gibt folgende Methoden zur Steuerung der Warteschlange:
get() - Mit get () wird ein Element aus der Warteschlange entfernt und zurückgegeben.
put() - Der Put fügt einer Warteschlange ein Element hinzu.
qsize() - qsize () gibt die Anzahl der Elemente zurück, die sich derzeit in der Warteschlange befinden.
empty()- Das empty () gibt True zurück, wenn die Warteschlange leer ist. sonst falsch.
full()- full () gibt True zurück, wenn die Warteschlange voll ist. sonst falsch.
Beispiel
#!/usr/bin/python
import Queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print "Starting " + self.name
process_data(self.name, self.q)
print "Exiting " + self.name
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print "%s processing %s" % (threadName, data)
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1
# Create new threads
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# Fill the queue
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# Wait for queue to empty
while not workQueue.empty():
pass
# Notify threads it's time to exit
exitFlag = 1
# Wait for all threads to complete
for t in threads:
t.join()
print "Exiting Main Thread"
Wenn der obige Code ausgeführt wird, wird das folgende Ergebnis erzeugt:
Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread