Une solution de contournement de Python Global Interpreter Lock (GIL) sur les systèmes multi-core en utilisant taskset sur Linux?

donc je viens de finir de regarder cette conférence sur le Global Interpreter Lock Python (GIL) http://blip.tv/file/2232410 .

l'essentiel est que la GIL est une assez bonne conception pour les systèmes à noyau unique (Python laisse essentiellement la gestion du thread/ordonnancement au système d'exploitation). Mais que cela peut sérieusement se retourner contre les systèmes multi-core et vous finissez avec IO threads intensifs étant lourdement bloqué par les threads intensifs CPU, le coût de la commutation de contexte, le problème ctrl-C [*] et ainsi de suite.

donc puisque le GIL nous limite à exécuter un programme Python sur un CPU, ma pensée est pourquoi ne pas l'accepter et utiliser simplement taskset sur Linux pour définir l'affinité du programme avec un certain core/cpu sur le système (surtout dans une situation où plusieurs applications Python fonctionnent sur un système multi-core)?

donc en fin de compte ma question Est la suivante: quelqu'un a-t-il essayé D'utiliser taskset sur Linux avec Applications Python (en particulier lorsqu'on exécute plusieurs applications sur un système Linux de sorte que plusieurs noyaux peuvent être utilisés avec une ou deux applications Python liées à un noyau spécifique) et si oui, quels en ont été les résultats? est-ce la peine de le faire? Est-ce que cela complique les choses pour certaines charges de travail? J'ai l'intention de le faire et de le tester (en gros voir si le programme prend plus ou moins de temps à s'exécuter), mais j'aimerais entendre d'autres personnes de votre expérience.

ajout: David Beazley (the guy donnant l'exposé dans la vidéo liée) a souligné que certaines extensions C/C++ libèrent manuellement la serrure GIL et si ces extensions sont optimisées pour multi-core (c.-à-d. analyse de données scientifiques ou numériques/etc.) alors plutôt que d'obtenir les avantages de multi-core pour le nombre crunching l'extension serait effectivement paralysé en ce qu'il est limité à un seul noyau (donc potentiellement ralentir votre programme de manière significative). D'un autre côté, si vous n'utilisez pas des extensions comme celle-ci

la raison pour laquelle je n'utilise pas le module multiprocessing est que (dans ce cas-ci) une partie du programme est fortement liée aux E/S réseau (requêtes HTTP), donc avoir un pool de threads de travail est un excellent moyen d'extraire les performances d'une boîte depuis qu'un thread déclenche une requête HTTP et puis depuis qu'il est en attente sur l'e/s donne la GIL et un autre thread peut faire sa chose, de sorte que cette partie du programme peut facilement exécuter plus de 100 threads sans blesser le CPU beaucoup et me laisser réellement utiliser le réseau la bande passante disponible. Quant à stackless Python/etc, Je ne suis pas trop intéressé à réécrire le programme ou à remplacer ma pile Python (la disponibilité serait également un problème).

[ * ] seul le thread principal peut recevoir des signaux, donc si vous envoyez un Ctrl-C, L'interpréteur Python essaie essentiellement d'obtenir que le thread principal tourne pour qu'il puisse gérer le signal, mais comme il ne contrôle pas directement quel thread est lancé (ceci est laissé au système d'exploitation), il dit essentiellement au système d'exploitation: continuez à changer de threads jusqu'à ce qu'il atteigne éventuellement le thread principal (qui si vous êtes malchanceux peut prendre un certain temps).

17
demandé sur Mike Pennington 2009-06-13 10:14:47

7 réponses

Je n'ai jamais entendu parler de quelqu'un utilisant taskset pour un gain de performance avec Python. Cela ne signifie pas que cela ne peut pas se produire dans votre cas, mais il est certain de publier vos résultats afin que d'autres puissent critiquer vos méthodes de benchmarking et fournir une validation.

personnellement cependant, je voudrais découpler vos threads d'e / s des threads liés au CPU en utilisant une file d'attente de messages. De cette façon, votre interface front end est maintenant complètement liée aux e/s Réseau (certaines avec l'interface HTTP, d'autres avec l'interface de file d'attente de messages).) et idéal pour votre situation de filetage. Ensuite, les processus intenses de CPU peuvent soit utiliser le multiprocessing, soit simplement être des processus individuels attendant que le travail arrive sur la file d'attente de messages.

à plus long terme, vous pourriez également envisager de remplacer votre ENTRÉE/SORTIE FILETÉE front-end par tordue ou quelque chose comme eventlets parce que, même si elles ne vont pas aider la performance, elles devraient améliorer l'évolutivité. Votre arrière-plan est maintenant déjà évolutif parce que vous peut exécuter votre file d'attente de message sur n'importe quel nombre de machines+cpus si nécessaire.

5
répondu Van Gale 2009-06-13 09:51:55

une autre solution est: http://docs.python.org/library/multiprocessing.html

Note 1: il s'agit de Non une limitation du langage Python, mais de L'implémentation du CPython.

Note 2: en ce qui concerne l'affinité, votre OS ne devrait pas avoir de problème à le faire lui-même.

8
répondu ynimous 2009-06-13 06:49:25

une solution intéressante est l'expérience rapportée par Ryan Kelly sur son blog: http://www.rfk.id.au/blog/entry/a-gil-adventure-threading2/

Les résultats semblent très satisfaisants.
3
répondu Leo Pepe 2011-11-20 20:57:53

j'ai trouvé la règle empirique suivante suffisante au fil des ans: si les travailleurs sont dépendants d'un état partagé, j'utilise un processus de multi-traitement par core (lié au CPU), et par core un ensemble fixe de threads de travail (lié à L'e/s). Le système d'exploitation s'occupera d'affecter les différents processus Python aux noyaux.

1
répondu wr. 2009-06-13 10:03:58

Le Python GIL est par l'interpréteur Python. Cela signifie que le seul moyen d'éviter des problèmes avec cela tout en faisant le multiprocessing est tout simplement commencer plusieurs interprètes (c.-à-d. en utilisant des processus séparés au lieu de threads pour la simultanéité) et puis en utilisant une autre primitive de la CIB pour la communication entre les processus (tels que les sockets). Ceci étant dit, La GIL n'est pas un problème lorsque vous utilisez des threads avec blocage des appels D'e/s.

le problème principal de la GIL comme mentionné plus haut c'est que vous ne pouvez pas exécuter 2 threads de code python différents en même temps. Un blocage de thread sur un appel I/O de blocage est bloqué et donc pas du code Python executin. Cela signifie qu'il ne bloque pas la GIL. Si vous avez deux tâches intensives en CPU dans des threads python séparés, C'est là que GIL tue le multi-processing en Python (seulement l'implémentation CPython, comme indiqué plus haut). Parce que le GIL empêche CPU #1 d'exécuter un thread python alors que CPU #0 est occupé à exécuter l'autre thread python.

1
répondu Merijn 2009-06-13 19:21:22

Jusqu'à ce que la GIL soit retirée de Python, les co-routines peuvent être utilisées à la place des threads. J'ai de bonne autorité le fait que cette stratégie a été mise en œuvre par deux start-ups réussies, utilisant les greenlets dans au moins un cas.

1
répondu 2009-06-17 07:43:33

C'est une question assez ancienne mais depuis chaque fois que je recherche des informations relatives à python et la performance sur les systèmes multi-core ce post est toujours sur la liste des résultats, Je ne laisserais pas ce passé devant moi un ne pas partager mes pensées.

vous pouvez utiliser le module multiprocessing qui, plutôt que de créer des threads pour chaque tâche, crée un autre processus de compier cpython interprétant votre code. Il ferait votre application pour profiter de multicore système. Le seul problème que je vois sur cette approche est que vous aurez un dépassement considérable en créant une nouvelle pile de processus entière sur la mémoire. ( http://en.wikipedia.org/wiki/Thread_ (computing)#How_threads_differ_from_processes )

Python Multiprocessing module: http://docs.python.org/dev/library/multiprocessing.html

"la raison pour laquelle je n'utilise pas le module multiprocesseur est que (dans ce cas) une partie du programme est fortement liée à l'e/s du réseau (requêtes HTTP), donc avoir un pool de threads de worker est un excellent moyen d'extraire les performances d'une boîte..."

à ce sujet, je suppose que vous pouvez aussi avoir un pool de processus: http://docs.python.org/dev/library/multiprocessing.html#using-a-pool-of-workers

Att, Leo

0
répondu Leo Pepe 2012-01-19 13:33:53