Wie verwendet man Threading in Python?

Ich versuche, Threading in Python zu verstehen. Ich habe mir die Dokumentation und die Beispiele angesehen, aber ehrlich gesagt sind viele Beispiele zu anspruchsvoll und ich habe Schwierigkeiten, sie zu verstehen.

Wie zeigen Sie deutlich, dass Aufgaben für Multithreading aufgeteilt werden?

Hier ein einfaches Beispiel: Sie müssen einige alternative URLs ausprobieren und den Inhalt der ersten URL zurückgeben, die reagiert.

import Queue
import threading
import urllib2

# called by each thread
def get_url(q, url):
    q.put(urllib2.urlopen(url).read())

theurls = ["http://google.com", "http://yahoo.com"]

q = Queue.Queue()

for u in theurls:
    t = threading.Thread(target=get_url, args = (q,u))
    t.daemon = True
    t.start()

s = q.get()
print s

Dies ist ein Fall, in dem Threading als einfache Optimierung eingesetzt wird: Jeder Subthread wartet darauf, dass eine URL aufgelöst und beantwortet wird, um ihren Inhalt in die Warteschlange zu stellen; jeder Thread ist ein Daemon (hält den Prozess nicht aufrecht, wenn der Hauptthread endet - das kommt häufiger vor als nicht); der Hauptthread startet alle Subthreads, führt ein get in der Warteschlange aus, um zu warten, bis einer von ihnen ein put ausgeführt hat, gibt dann die Ergebnisse aus und beendet sich (was alle Subthreads, die noch laufen könnten, beendet, da sie Daemon-Threads sind).

Die korrekte Verwendung von Threads in Python ist immer mit E/A-Operationen verbunden (da CPython ohnehin nicht mehrere Kerne verwendet, um CPU-gebundene Aufgaben auszuführen, besteht der einzige Grund für Threading darin, den Prozess nicht zu blockieren, während auf eine E/A gewartet wird). Warteschlangen sind übrigens fast immer der beste Weg, um Arbeit an Threads zu verteilen und/oder die Ergebnisse der Arbeit zu sammeln, und sie sind intrinsisch thread-sicher, so dass Sie sich keine Gedanken über Sperren, Bedingungen, Ereignisse, Semaphoren und andere Konzepte zur Koordination/Kommunikation zwischen Threads machen müssen.

Kommentare (14)

Hinweis: Für eine tatsächliche Parallelisierung in Python sollten Sie das Multiprocessing-Modul verwenden, um mehrere Prozesse zu forken, die parallel ausgeführt werden (aufgrund der globalen Interpreter-Sperre bieten Python-Threads zwar eine Verschachtelung, werden aber in Wirklichkeit seriell und nicht parallel ausgeführt und sind nur nützlich, wenn E/A-Operationen verschachtelt werden).

Wenn Sie jedoch lediglich nach einer Verschachtelung suchen (oder E/A-Operationen durchführen, die trotz der globalen Interpretersperre parallelisiert werden können), dann ist das Threading-Modul der richtige Ort, um damit zu beginnen. Als wirklich einfaches Beispiel betrachten wir das Problem der Summierung eines großen Bereichs durch parallele Addition von Teilbereichen:

import threading

class SummingThread(threading.Thread):
     def __init__(self,low,high):
         super(SummingThread, self).__init__()
         self.low=low
         self.high=high
         self.total=0

     def run(self):
         for i in range(self.low,self.high):
             self.total+=i

thread1 = SummingThread(0,500000)
thread2 = SummingThread(500000,1000000)
thread1.start() # This actually causes the thread to run
thread2.start()
thread1.join()  # This waits until the thread has completed
thread2.join()  
# At this point, both threads have completed
result = thread1.total + thread2.total
print result

Beachten Sie, dass das obige Beispiel sehr dumm ist, da es absolut keine E/A durchführt und in CPython aufgrund der globalen Interpretersperre seriell ausgeführt wird, wenn auch verschachtelt (mit dem zusätzlichen Overhead der Kontextumschaltung).

Kommentare (8)

Wie bereits erwähnt, kann CPython aufgrund von GIL Threads nur für I\O-Wartezeiten verwenden. Wenn Sie von mehreren Kernen für CPU-gebundene Aufgaben profitieren wollen, verwenden Sie multiprocessing:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
Kommentare (5)