Python Language
Processen en threads
Zoeken…
Invoering
De meeste programma's worden regel voor regel uitgevoerd, waarbij slechts één proces tegelijk wordt uitgevoerd. Threads laten meerdere processen onafhankelijk van elkaar stromen. Door meerdere processors in te rijgen, kunnen programma's meerdere processen tegelijkertijd uitvoeren. Dit onderwerp beschrijft de implementatie en het gebruik van threads in Python.
Wereldwijd tolkenslot
Multithreading-prestaties van Python kunnen vaak lijden onder de Global Interpreter Lock . Kortom, hoewel u meerdere threads in een Python-programma kunt hebben, kan slechts één bytecode-instructie tegelijkertijd parallel worden uitgevoerd, ongeacht het aantal CPU's.
Als zodanig kan multithreading in gevallen waarin bewerkingen worden geblokkeerd door externe gebeurtenissen - zoals netwerktoegang - behoorlijk effectief zijn:
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
Merk op dat hoewel elk process
2 seconden duurde om uit te voeren, de vier processen samen in staat waren om effectief parallel te lopen, in totaal 2 seconden duren.
Multithreading in gevallen waarin intensieve berekeningen worden uitgevoerd in Python-code - zoals veel berekeningen - leidt echter niet tot veel verbetering en kan zelfs langzamer zijn dan parallel lopen:
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
In het laatste geval kan multiprocessing effectief zijn, omdat meerdere processen natuurlijk meerdere instructies tegelijkertijd kunnen uitvoeren:
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
Uitgevoerd in meerdere threads
Gebruik threading.Thread
om een functie in een andere thread uit te voeren.
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
Uitgevoerd in meerdere processen
Gebruik multiprocessing.Process
om een functie in een ander proces uit te voeren. De interface is vergelijkbaar met 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
Deelstatus tussen threads
Omdat alle threads in hetzelfde proces worden uitgevoerd, hebben alle threads toegang tot dezelfde gegevens.
Gelijktijdige toegang tot gedeelde gegevens moet echter worden beveiligd met een slot om synchronisatieproblemen te voorkomen.
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}
Deelstatus tussen processen
Code die in verschillende processen wordt uitgevoerd, deelt standaard niet dezelfde gegevens. De multiprocessing
module bevat echter primitieven om waarden over meerdere processen te delen.
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