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



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow