Suche…


Einführung

Die meisten Programme werden Zeile für Zeile ausgeführt, wobei jeweils nur ein Prozess ausgeführt wird. Durch Threads können mehrere Prozesse unabhängig voneinander fließen. Durch das Threading mit mehreren Prozessoren können Programme mehrere Prozesse gleichzeitig ausführen. In diesem Thema wird die Implementierung und Verwendung von Threads in Python beschrieben.

Globale Interpreter-Sperre

Die Leistung von Python-Multithreading kann häufig durch die Global Interpreter Lock beeinträchtigt werden . Kurz gesagt, obwohl in einem Python-Programm mehrere Threads vorhanden sein können, kann nur eine Bytecode-Anweisung unabhängig von der Anzahl der CPUs gleichzeitig ausgeführt werden.

Daher kann Multithreading in Fällen, in denen Vorgänge durch externe Ereignisse blockiert werden, wie z. B. Netzwerkzugriff, recht effektiv sein:

import threading
import time


def process():
    time.sleep(2)


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.00s
# Out: Four runs took 2.00s

Obwohl jeder process zwei Sekunden für die Ausführung benötigte, konnten die vier Prozesse zusammen effektiv ausgeführt werden, was insgesamt zwei Sekunden dauerte.

Multithreading führt jedoch in Fällen, in denen intensive Berechnungen in Python-Code ausgeführt werden, beispielsweise bei vielen Berechnungen, zu keiner großen Verbesserung und kann sogar langsamer sein als das parallele Ausführen:

import threading
import time


def somefunc(i):
    return i * i

def otherfunc(m, i):
    return m + i

def process():
    for j in range(100):
        result = 0
        for i in range(100000):
            result = otherfunc(result, somefunc(i))


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.05s
# Out: Four runs took 14.42s

Im letzteren Fall kann Multiprocessing effektiv sein, da mehrere Prozesse natürlich mehrere Anweisungen gleichzeitig ausführen können:

import multiprocessing
import time


def somefunc(i):
    return i * i

def otherfunc(m, i):
    return m + i

def process():
    for j in range(100):
        result = 0
        for i in range(100000):
            result = otherfunc(result, somefunc(i))


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
processes = [multiprocessing.Process(target=process) for _ in range(4)]
for p in processes:
    p.start()
for p in processes:
    p.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.07s
# Out: Four runs took 2.30s

Ausführen in mehreren Threads

Verwenden Sie threading.Thread , um eine Funktion in einem anderen Thread auszuführen.

import threading
import os

def process():
    print("Pid is %s, thread id is %s" % (os.getpid(), threading.current_thread().name))

threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
    
# Out: Pid is 11240, thread id is Thread-1
# Out: Pid is 11240, thread id is Thread-2
# Out: Pid is 11240, thread id is Thread-3
# Out: Pid is 11240, thread id is Thread-4

Ausführen in mehreren Prozessen

Verwenden Sie multiprocessing.Process , um eine Funktion in einem anderen Prozess auszuführen. Die Schnittstelle ähnelt threading.Thread :

import multiprocessing
import os

def process():
    print("Pid is %s" % (os.getpid(),))

processes = [multiprocessing.Process(target=process) for _ in range(4)]
for p in processes:
    p.start()
for p in processes:
    p.join()
    
# Out: Pid is 11206
# Out: Pid is 11207
# Out: Pid is 11208
# Out: Pid is 11209

Status zwischen Threads teilen

Da alle Threads in demselben Prozess ausgeführt werden, haben alle Threads Zugriff auf dieselben Daten.

Der gleichzeitige Zugriff auf gemeinsam genutzte Daten sollte jedoch durch eine Sperre geschützt werden, um Synchronisierungsprobleme zu vermeiden.

import threading

obj = {}
obj_lock = threading.Lock()

def objify(key, val):
    print("Obj has %d values" % len(obj))
    with obj_lock:
        obj[key] = val
    print("Obj now has %d values" % len(obj))

ts = [threading.Thread(target=objify, args=(str(n), n)) for n in range(4)]
for t in ts:
    t.start()
for t in ts:
    t.join()
print("Obj final result:")
import pprint; pprint.pprint(obj)

# Out: Obj has 0 values
# Out:  Obj has 0 values
# Out: Obj now has 1 values
# Out: Obj now has 2 valuesObj has 2 values
# Out: Obj now has 3 values
# Out: 
# Out:  Obj has 3 values
# Out: Obj now has 4 values
# Out: Obj final result:
# Out: {'0': 0, '1': 1, '2': 2, '3': 3}

Status zwischen Prozessen teilen

Code, der in verschiedenen Prozessen ausgeführt wird, verwendet standardmäßig nicht die gleichen Daten. Das multiprocessing Modul enthält jedoch Grundelemente, die das gemeinsame Nutzen von Werten über mehrere Prozesse unterstützen.

import multiprocessing

plain_num = 0
shared_num = multiprocessing.Value('d', 0)
lock = multiprocessing.Lock()

def increment():
    global plain_num
    with lock:
        # ordinary variable modifications are not visible across processes
        plain_num += 1
        # multiprocessing.Value modifications are
        shared_num.value += 1

ps = [multiprocessing.Process(target=increment) for n in range(4)]
for p in ps:
    p.start()
for p in ps:
    p.join()

print("plain_num is %d, shared_num is %d" % (plain_num, shared_num.value))

# Out: plain_num is 0, shared_num is 4



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow