Je développais une application sur gae en utilisant python 2.7, un appel ajax demande des données à une API, une seule demande pouvait prendre environ 200 ms, mais lorsque j'ouvre deux navigateurs et fais deux demandes à un moment très proche, cela prend plus que le double, j'ai essayé de tout mettre dans les threads mais cela n'a pas fonctionné .. (cela se produit lorsque l'application est en ligne, pas seulement sur le serveur de développement)

J'ai donc écrit ce test simple pour voir s'il s'agit d'un problème en python en général (en cas d'attente trop chargée), voici le code et le résultat:

def work():
    t = datetime.now()
    print threading.currentThread(), t
    i = 0
    while i < 100000000:
        i+=1
    t2 = datetime.now()
    print threading.currentThread(), t2, t2-t

if __name__ == '__main__': 
    print "single threaded:"
    t1 = threading.Thread(target=work)
    t1.start()
    t1.join()

    print "multi threaded:"
    t1 = threading.Thread(target=work)
    t1.start()
    t2 = threading.Thread(target=work)
    t2.start()
    t1.join()
    t2.join()

Le résultat sur mac os x, core i7 (4 cœurs, 8 threads), python2.7:

single threaded:
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:07.763146
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:13.091614 0:00:05.328468

multi threaded:
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:13.091952
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:13.102250
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:29.221050 0:00:16.118800
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:29.237512 0:00:16.145560

C'est assez choquant !! si un seul thread prenait 5 secondes pour le faire .. Je pensais que démarrer deux threads en même temps prendrait le même temps pour terminer les deux tâches, mais cela prend presque le triple du temps .. cela rend l'idée de threading inutile, car il serait plus rapide de les faire séquentiellement!

Qu'est-ce que j'oublie ici..

7
Mohamed Khamis 6 déc. 2011 à 21:01

3 réponses

Meilleure réponse

David Beazley a fait un exposé sur ce problème lors de PyCon 2010 . Comme d'autres l'ont déjà indiqué, pour certaines tâches, l'utilisation de threads en particulier avec plusieurs cœurs peut entraîner des performances plus lentes que la même tâche effectuée par un seul thread. Le problème, selon Beazley, concernait plusieurs cœurs ayant une "bataille GIL":

enter image description here

Pour éviter les conflits GIL, vous pouvez obtenir de meilleurs résultats en exécutant les tâches dans des processus distincts au lieu de threads distincts. Le module multiprocessing fournit un moyen pratique de le faire, d'autant plus que l'API multiprocessing est très similaire à l'API de threading.

import multiprocessing as mp
import datetime as dt
def work():
    t = dt.datetime.now()
    print mp.current_process().name, t
    i = 0
    while i < 100000000:
        i+=1
    t2 = dt.datetime.now()
    print mp.current_process().name, t2, t2-t

if __name__ == '__main__': 
    print "single process:"
    t1 = mp.Process(target=work)
    t1.start()
    t1.join()

    print "multi process:"
    t1 = mp.Process(target=work)
    t1.start()
    t2 = mp.Process(target=work)
    t2.start()
    t1.join()
    t2.join()

Les rendements

single process:
Process-1 2011-12-06 12:34:20.611526
Process-1 2011-12-06 12:34:28.494831 0:00:07.883305
multi process:
Process-3 2011-12-06 12:34:28.497895
Process-2 2011-12-06 12:34:28.503433
Process-2 2011-12-06 12:34:36.458354 0:00:07.954921
Process-3 2011-12-06 12:34:36.546656 0:00:08.048761

PS. Comme l'a souligné zeekay dans les commentaires, la bataille de GIL n'est sévère que pour les tâches liées au processeur. Cela ne devrait pas être un problème pour les tâches liées aux E / S.

9
unutbu 6 déc. 2011 à 17:41

L'interpréteur CPython ne permettra pas l'exécution de plus d'un thread. en savoir plus sur GIL http://wiki.python.org/moin/GlobalInterpreterLock

Ainsi, certaines tâches ne peuvent pas être effectuées simultanément de manière efficace dans CPython avec des threads.

Si vous voulez faire des choses en parallèle dans GAE, démarrez-les en parallèle avec des requêtes séparées.

Vous pouvez également consulter le wiki parallèle Python http://wiki.python.org/moin/ParallelProcessing

4
bpgergo 6 déc. 2011 à 17:09

Je regarderais où va le temps. Supposons, par exemple, que le serveur ne puisse répondre qu'à une requête toutes les 200 ms. Ensuite, vous ne pouvez rien faire, vous n'aurez qu'une seule réponse toutes les 200 ms car c'est tout ce que le serveur peut vous fournir.

1
David Schwartz 6 déc. 2011 à 17:09