Python est un langage qui s'exécute dans un interpréteur. Selon les recherches, Python possède un verrou global (GIL). Lors de l'utilisation du multi-threading (Thread), il ne peut pas tirer parti du multi-cœur. Cependant, l'utilisation du multi-processus (Multiprocess) peut tirer parti des avantages du multi-cœur pour réellement améliorer l'efficacité.

Expérience de comparaison

Selon les informations, si le processus multithread estintensif en CPUalors le multi-threading ne peut pas beaucoup améliorer l'efficacité ; au contraire, il peut même diminuer l'efficacité en raison de commutations fréquentes de threads, donc le multi-processus est recommandé ; s'il estintensif en E/Salors les processus multithread peuvent utiliser le temps d'inactivité pendant les attentes de blocage d'E/S pour exécuter d'autres threads, ce qui améliore l'efficacité. Par conséquent, nous comparons l'efficacité de différents scénarios au moyen d'expériences.

Système d'exploitation CPU Mémoire Disque dur
Windows 10 Double cœur 8GB Disque dur mécanique

(1) Importer les modules requis

import requests
import time
from threading import Thread
from multiprocessing import Process

(2) Définir une fonction de calcul intensive en CPU

def count(x, y):
    # 使程序完成50万计算
    c = 0
    while c < 500000:
        c += 1
        x += x
        y += y

(3) Définir une fonction de lecture/écriture de fichier intensive en E/S

def write():
    f = open("test.txt", "w")
    for x in range(5000000):
        f.write("testwrite\n")
    f.close()
def read():
    f = open("test.txt", "r")
    lines = f.readlines()
    f.close()

(4) Définir une fonction de requête réseau

_head = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'}
url = "http://www.tieba.com"
def http_request():
    try:
        webPage = requests.get(url, headers=_head)
        html = webPage.text
        return {"context": html}
    except Exception as e:
        return {"error": e}

(5) Tester le temps nécessaire à l'exécution linéaire d'opérations intensives en E/S, d'opérations intensives en CPU et d'opérations intensives en requêtes réseau

# CPU密集操作
t = time.time()
for x in range(10):
    count(1, 1)
print("Line cpu", time.time() - t)
# IO密集操作
t = time.time()
for x in range(10):
    write()
    read()
print("Line IO", time.time() - t)
# 网络请求密集型操作
t = time.time()
for x in range(10):
    http_request()
print("Line Http Request", time.time() - t)

Sortie

  • Intensif en CPU : 95.6059999466, 91.57099986076355, 92.52800011634827, 99.96799993515015

  • Intensif en E/S : 24.25, 21.76699995994568, 21.769999980926514, 22.060999870300293

  • Intensif en requêtes réseau : 4.519999980926514, 8.563999891281128, 4.371000051498413, 4.522000074386597, 14.671000003814697

(6) Tester le temps nécessaire à l'exécution concurrente multithread d'opérations intensives en CPU

counts = []
t = time.time()
for x in range(10):
    thread = Thread(target=count, args=(1,1))
    counts.append(thread)
    thread.start()
e = counts.__len__()
while True:
    for th in counts:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print(time.time() - t)

Sortie : 25.69700002670288、24.02400016784668

(7) Tester le temps nécessaire à l'exécution concurrente multithread d'opérations intensives en E/S

def io():
    write()
    read()

t = time.time()
ios = []
t = time.time()
for x in range(10):
    thread = Thread(target=count, args=(1,1))
    ios.append(thread)
    thread.start()

e = ios.__len__()
while True:
    for th in ios:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print(time.time() - t)

Sortie : 99.9240000248 、101.26400017738342、102.32200002670288

(8) Tester le temps requis pour l'exécution concurrente multithread d'opérations intensives en réseau

t = time.time()
ios = []
t = time.time()
for x in range(10):
    thread = Thread(target=http_request)
    ios.append(thread)
    thread.start()

e = ios.__len__()
while True:
    for th in ios:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print("Thread Http Request", time.time() - t)

Sortie : 0.7419998645782471、0.3839998245239258、0.3900001049041748

(9) Tester le temps requis pour l'exécution concurrente multiprocessus d'opérations intensives en CPU

counts = []
t = time.time()
for x in range(10):
    process = Process(target=count, args=(1,1))
    counts.append(process)
    process.start()
e = counts.__len__()
while True:
    for th in counts:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print("Multiprocess cpu", time.time() - t)

Sortie : 54.342000007629395、53.437999963760376

(10) Tester l'exécution concurrente multiprocessus d'opérations intensives en E/S

t = time.time()
ios = []
t = time.time()
for x in range(10):
    process = Process(target=io)
    ios.append(process)
    process.start()

e = ios.__len__()
while True:
    for th in ios:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print("Multiprocess IO", time.time() - t)

Sortie : 12.509000062942505、13.059000015258789

(11) Tester l'exécution concurrente multiprocessus d'opérations intensives en requêtes HTTP

t = time.time()
httprs = []
t = time.time()
for x in range(10):
    process = Process(target=http_request)
    ios.append(process)
    process.start()

e = httprs.__len__()
while True:
    for th in httprs:
        if not th.is_alive():
            e -= 1
    if e <= 0:
        break
print("Multiprocess Http Request", time.time() - t)

Sortie : 0.5329999923706055、0.4760000705718994

Résultats expérimentaux

Opérations intensives en CPU Opérations intensives en E/S Opérations intensives en requêtes réseau
Opérations linéaires 94.91824996469 22.46199995279 7.3296000004
Opérations multithread 101.1700000762 24.8605000973 0.5053332647
Opérations multiprocessus 53.8899999857 12.7840000391 0.5045000315

D'après les résultats ci-dessus, nous pouvons constater :

  • Le multithreading ne semble pas non plus présenter d'avantage significatif dans les opérations intensives en E/S (peut-être que si les tâches d'E/S étaient plus lourdes, l'avantage se manifesterait). Dans les opérations intensives en CPU, il est clairement moins performant que l'exécution linéaire monothread. Cependant, pour les opérations comme les requêtes réseau qui provoquent un blocage de thread en attente active, le multithreading présente un avantage très significatif.

  • Le multi-processus présente des avantages de performance dans les scénarios intensifs en CPU, intensifs en E/S et intensifs en requêtes réseau (opérations où des blocages de thread se produisent fréquemment). Cependant, pour les opérations similaires à celles intensives en requêtes réseau, il est presque identique au multithreading, mais consomme davantage de ressources telles que le CPU. Par conséquent, dans ce cas, nous pouvons choisir d'exécuter en multithreading.

Adresse d'origine : http://blog.atomicer.cn/2016/09/30/Python%E4%B8%AD%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%92%8C%E5%A4%9A%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%AF%B9%E6%AF%94/