Une tentative précoce de suppression de Python GIL a entraîné de mauvaises performances: pourquoi?

13

Ce post du créateur de Python, Guido Van Rossum, mentionne une tentative précoce de supprimer le GIL de Python:

Cela a été essayé auparavant, avec des résultats décevants, c'est pourquoi je suis réticent à y consacrer beaucoup d'efforts moi-même. En 1999, Greg Stein (avec Mark Hammond?) A produit une fourchette de Python (1.5 je crois) qui a supprimé le GIL, le remplaçant par des verrous à grain fin sur toutes les structures de données mutables. Il a également soumis des correctifs qui supprimaient la plupart des dépendances sur les structures de données globales mutables, ce que j'ai accepté. Cependant, après l'analyse comparative, il a été démontré que même sur la plate-forme avec la primitive de verrouillage la plus rapide (Windows à l'époque), elle ralentissait l'exécution à un seul thread près de deux fois, ce qui signifie que sur deux processeurs, vous pouviez obtenir un peu plus de travail fait sans le GIL que sur un seul processeur avec le GIL. Ce n'était pas suffisant et le patch de Greg a disparu dans l'oubli. (Voir le résumé de Greg sur la performance.)

Je peux difficilement contester les résultats réels, mais je me demande vraiment pourquoi cela s'est produit. Vraisemblablement, la principale raison pour laquelle la suppression du GIL de CPython est si difficile est due au système de gestion de la mémoire de comptage des références. Un programme Python typique appel Py_INCREFet des Py_DECREFmilliers ou des millions de fois, ce qui en fait un point de contention clé si nous devions envelopper les verrous autour.

Mais, je ne comprends pas pourquoi l'ajout de primitives atomiques ralentirait un programme à thread unique . Supposons que nous venons de modifier CPython afin que la variable refcount dans chaque objet Python soit une primitive atomique. Et puis nous faisons juste un incrément atomique (instruction fetch-and-add) quand nous avons besoin d'incrémenter le compte de référence. Cela rendrait le comptage de référence Python sûr pour les threads et ne devrait pas avoir de pénalité de performances sur une application à un seul thread, car il n'y aurait pas de conflit de verrouillage.

Mais hélas, beaucoup de gens plus intelligents que moi ont essayé et échoué, alors il me manque évidemment quelque chose ici. Quel est le problème avec la façon dont je regarde ce problème?

Siler
la source
1
Notez que l'opération refcount ne serait pas le seul endroit nécessitant une synchronisation. La citation mentionne "des verrous à grain fin sur toutes les structures de données mutables" qui, je suppose, incluent au moins un mutex pour chaque objet de liste et de dictionnaire. De plus, je ne pense pas que les opérations atomiques entières soient aussi efficaces que l'équivalent non atomique indépendamment de la contention, avez-vous une source pour cela?
simplement parce que les opérations atomiques sont plus lentes que les équivalents non atomiques. Ce n'est pas parce que c'est une instruction unique que c'est trivial sous le capot. Voir ceci pour une discussion
Móż

Réponses:

9

Je ne suis pas familier avec la fourchette Greg Stein Python, alors escomptez cette comparaison comme analogie historique spéculative si vous le souhaitez. Mais c'était exactement l'expérience historique de nombreuses bases de code d'infrastructure passant d'une implémentation à une seule à plusieurs threads.

Essentiellement, toutes les implémentations Unix que j'ai étudiées dans les années 1990 - AIX, DEC OSF / 1, DG / UX, DYNIX, HP-UX, IRIX, Solaris, SVR4 et SVR4 MP - ont toutes subi exactement ce type de "nous avons mis en verrouillage plus fin - maintenant c'est plus lent !! " problème. Les SGBD que j'ai suivis - DB2, Ingres, Informix, Oracle et Sybase - ils sont tous passés par là aussi.

J'ai entendu dire que «ces changements ne nous ralentiront pas lorsque nous exécuterons un seul thread» un million de fois. Cela ne fonctionne jamais de cette façon. Le simple fait de vérifier conditionnellement "exécutons-nous du multithread ou non?" ajoute un réel surcoût, en particulier sur les processeurs hautement pipelinés. Les opérations atomiques et les verrous rotatifs occasionnels ajoutés pour garantir l'intégrité des structures de données partagées doivent être appelés assez souvent, et ils sont très lents. Les primitives de verrouillage / synchronisation de première génération étaient également lentes. La plupart des équipes d'implémentation finissent par ajouter plusieurs classes de primitives, dans différentes «forces», selon la quantité de protection de verrouillage nécessaire à divers endroits. Ensuite, ils réalisent où ils ont initialement giflé les primitives de verrouillage n'était pas vraiment le bon endroit, ils ont donc dû profiler, concevoir autour des goulots d'étranglement trouvés, et systématiquement en rotation. Certains de ces points de blocage ont finalement obtenu une accélération du système d'exploitation ou du matériel, mais toute cette évolution a pris 3-5 ans, au minimum. Pendant ce temps, les versions MP ou MT boitaient, en termes de performances.

Des équipes de développement par ailleurs sophistiquées ont fait valoir que de tels ralentissements sont fondamentalement une réalité persistante et insoluble. IBM, par exemple, a refusé d'activer AIX pour SMP pendant au moins 5 ans après la compétition, affirmant que le thread unique était tout simplement meilleur. Sybase a utilisé certains des mêmes arguments. La seule raison pour laquelle certaines équipes sont finalement venues est que les performances d'un seul thread ne pouvaient plus être raisonnablement améliorées au niveau du processeur. Ils ont été contraints de passer en MP / MT ou d'accepter d'avoir un produit de plus en plus non compétitif.

La concurrence active est HARD. Et c'est trompeur. Tout le monde s'y précipite en pensant "ce ne sera pas si mal". Ensuite, ils ont frappé les sables mouvants et doivent traverser. J'ai vu cela se produire avec au moins une douzaine d'équipes intelligentes de marque bien financées. En général, il a semblé qu'il fallait au moins cinq ans après avoir choisi le multi-thread pour "revenir là où ils devraient être, en termes de performances" avec les produits MP / MT; la plupart amélioraient encore significativement l'efficacité / l'évolutivité MP / MT, même dix ans après avoir effectué le changement.

Donc, ma spéculation est que, en l'absence de l'approbation et du soutien du GvR, personne n'a pris le long chemin pour Python et son GIL. Même s'ils devaient le faire aujourd'hui, ce serait un délai Python 4.x avant de dire "Wow! Nous sommes vraiment sur la bosse MT!"

Il y a peut-être une magie qui sépare Python et son runtime de tous les autres logiciels d'infrastructure avec état - tous les runtimes de langage, les systèmes d'exploitation, les moniteurs de transactions et les gestionnaires de bases de données qui ont précédé. Mais si c'est le cas, c'est unique ou presque. Toutes les autres personnes supprimant un équivalent GIL ont pris plus de cinq ans d'efforts et d'investissements durs et engagés pour passer de MT-pas à MT-hot.

Jonathan Eunice
la source
2
+1 Il a fallu environ ce temps pour Tcl multi-thread avec une assez petite équipe de développeurs. Le code était MT-safe avant cela, mais avait des problèmes de performances désagréables, principalement dans la gestion de la mémoire (ce qui, je le soupçonne, est un domaine très chaud pour les langages dynamiques). Cependant, l'expérience ne se transmet pas vraiment à Python autrement que dans les termes les plus généraux; les deux langues ont des modèles de filetage complètement différents. Juste… attendez-vous à un slog et attendez-vous à des bugs étranges…
Donal Fellows
-1

Une autre hypothèse folle: en 1999, Linux et les autres Unices n'avaient pas de synchronisation performante comme c'est le cas aujourd'hui futex(2)( http://en.wikipedia.org/wiki/Futex ). Ceux-ci sont arrivés vers 2002 (et ont été fusionnés en 2.6 vers 2004).

Étant donné que toutes les structures de données intégrées doivent être synchronisées, le verrouillage coûte cher. Ӎσᶎ a déjà souligné que les opérations atomiques ne sont pas nécessairement bon marché.

Sahib
la source
1
Avez-vous quelque chose à l'appui de cela? ou est-ce presque de la spéculation?
1
La citation GvR décrit les performances "sur la plate-forme avec la primitive de verrouillage la plus rapide (Windows à l'époque)", donc les verrous lents sur Linux ne sont pas pertinents.