Python Language Global Interpreter Lock


Exemple

Les performances du multithreading Python peuvent souvent être affectées par le Global Interpreter Lock . En bref, même si vous pouvez avoir plusieurs threads dans un programme Python, une seule instruction de bytecode peut s'exécuter en parallèle à tout moment, quel que soit le nombre de processeurs.

En tant que tel, le multithreading dans les cas où les opérations sont bloquées par des événements externes - comme l’accès au réseau - peut être très efficace:

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

Notez que même si chaque process pris 2 secondes pour s’exécuter, les quatre processus ensemble ont pu être exécutés efficacement en parallèle, en prenant 2 secondes au total.

Cependant, le multithreading dans les cas où des calculs intensifs sont effectués en code Python - comme beaucoup de calculs - ne se traduit pas par une amélioration considérable et peut même être plus lent que l'exécution en parallèle:

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

Dans ce dernier cas, le multitraitement peut être efficace car plusieurs processus peuvent, bien entendu, exécuter plusieurs instructions simultanément:

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