8
votes

Il y a quelque chose de similaire au fil de Java.yield () à Python? Est-ce que cela a même un sens?

Je veux dire à mes fils Python de céder, et évitez donc de le charger inutilement de la CPU. En Java, vous pouvez le faire en utilisant la fonction thread.yield () . Je ne pense pas qu'il y ait quelque chose de similaire dans Python, j'ai donc utilisé temps.sleep (t) t = 0.00001 . Pour t = 0 il semble n'y avoir aucun effet.

Je pense que peut-être qu'il y a quelque chose que je ne comprends pas correctement sur le modèle de threading de Python, et donc la raison du fichier manquant () . Quelqu'un peut-il me clarifier cela? Merci!

PS: C'est ce que la documentation pour Java's thread.yield () dit:

provoque le fil actuellement exécutant objet à mettre temporairement en pause et à permettre autres threads à exécuter.


2 commentaires

quand t = 0, il cède pour tout autre fil prêt


D'accord. Merci. J'ai essayé cela mais ne semble pas fonctionner. Peut-être que je mesurise de manière incorrecte.


3 Réponses :


11
votes

2 commentaires

Mon problème est que temps.sleep (0) ne semble avoir aucun effet. Merci pour la référence.


HRMS, impair, si cela ne fonctionne pas quelque chose d'autre bizarre doit se produire. :)



4
votes

L'interprète passera d'un fil à une autre périodiquement sans votre intervention - vous n'avez pas besoin de dire au système de ne pas "porc" un fil.

Cependant, dans des circonstances normales, un seul fil de python est en cours d'exécution à la fois. (Les exceptions ont tendance à tourner autour des temps lorsque les threads attendent l'entrée des périphériques externes tels que le disque dur ou le réseau.) Ceci est dû au Verrouillage d'interprétation mondial . Cela signifie toutefois que vous n'obtenez probablement pas autant d'avantages des threads de Python que vous le feriez en Java ou dans de nombreuses autres langues. Se déplacer ce problème n'est pas nécessairement trivial, bien que de passer à multiprocessing au lieu de multithreading est un bonne approche, si possible.

Cependant, ce que vous voulez faire semble imparfait dans un sens - si vous avez 2 threads et ils ont tous les deux du travail à faire, vous ne devriez pas avoir à écrire du code côté application pour basculer entre eux. C'est le travail du système d'exploitation ou de la machine virtuelle. Si vous vous trouvez en train de dire un fil de «faire moins» parce que vous souhaitez favoriser un autre fil en termes de temps de processeur, plutôt que d'ajouter un rendement arbitraire ou dormir, vous devez probablement régler les priorités de fil. (Bien que encore une fois, cela peut ne pas avoir beaucoup de sens dans Python compte tenu de la présence du verrouillage de l'interprète mondial.)


8 commentaires

Que se passe-t-il lorsqu'un fil ne cède pas, est qu'il commence à affamer les autres threads. Java et C (Pthreads) ont donné des fonctions pour indiquer au planificateur que le thread est "libre". La réponse ici: Stackoverflow.com/Questtions/787803/... semble donner quelques perspectives supplémentaires, mais il semble que je ne puisse pas me contourner.


Je pense que vous êtes mal compris que les threads fonctionnent sur la plupart des systèmes. Le système bascule automatiquement entre les threads de manière très régulière afin que toutes les threads se rendent à courir. (Ceci s'appelle «préemption» ou «multitâche préventive».) Vous n'avez pas besoin de basculer manuellement entre eux sur Java ou Python. Des méthodes telles que le rendement () sur ces systèmes sont une optimisation mineure et non une exigence.


Céder pourrait être utile si vous êtes assis sur une boucle et que vous faites une attente occupée (par exemple, lorsque vous indiquez constamment au planificateur que vous ne faites pas de travail. Les priorités de thread ne fonctionnent pas ici car le thread de vote n'a pas de priorité inférieure, mais il suffit de «travailler moins à faire» lorsque vous attendez. Notez que, idéalement, vous préférez ne pas planifier le thread de l'interrogation jusqu'à ce que l'intrigue d'intérêt se produise, mais si vous avez recours à l'interrogation, cela signifie probablement que vous ne pouvez pas faire cela de toute façon.


Le problème Gil en Python est qu'un fil assis sur une boucle à attendre occupé empêchera d'autres threads de faire du travail utile (jusqu'à ce qu'il soit préempté). Le céder est donc une belle optimisation dans ce cas.


Non non. Je sais sur la préemption. Le rendement Je fais référence à (dans le cas de Java ou de Pthreads) conseiller simplement le planificateur. C'est un moyen de suggérer un point de préemption. Comme vous le dites, c'est une optimisation. J'ai besoin d'aller en savoir plus sur le gil. Merci.


Si votre thread perd de temps à faire quelque chose, vous n'avez pas besoin de faire tout cela souvent, il serait préférable de trouver un moyen d'avoir le système de réveiller votre fil quand il y a du travail à faire, au lieu d'ajouter de minuscules couches ou des rendements qui sont un hack au mieux. La bibliothèque de threading de Python fournit des variables de condition, par exemple.


Merci @kylotan, la condition variables est ce que je cherchais. Et vous avez raison, dans ce cas, il y a de minuscules couchages ou attendez un piratage, et donc ma question initiale.


En outre, il était très utile de lire la mise en œuvre de file d'attente et collections.deque .



0
votes

thread.yield () est absent de Python car il a peut-être été oublié ou que le concepteur pensait que toutes les problèmes de synchronisation et de communication interprocesses sont satisfables sans thread.yield ().

J'utiliserais thread.yield () pour le numéro suivant:

E.g. Il y a une file d'attente de travail et il y a 2 fils de travail pouvant aller chercher des entrées de la file d'attente de travail et placer des entrées dans la file d'attente. Une façon de résoudre est d'utiliser la classe filetage.conition. Lorsque le travailleur 'B' veut chercher une entrée de la file d'attente, mais la file d'attente est vide, il va d'attendre l'état (condition.Wait ()). Lorsque le travailleur 'A' place l'entrée dans la file d'attente, il se réveille «B» (condition.Notify ()). À ce stade, céder est essentiel, car si le travailleur 'A' ne cédit pas ici, le travailleur 'A' peut aller chercher la tâche avant le travailleur de réveil 'B' qui provoque une question de condition de course.

Je me demande comment il est résoluble sans fil.yield ().


4 commentaires

Vous n'avez pas demandé pourquoi thread.yield () est manquant à Python? Je ne pense pas qu'une explication de thread.yield () convient à la question.


Sûr. Mais beaucoup de gens se disputent que ce rendement n'est pas nécessaire, en raison de la préemption. Je pense que le fil.yield () est manquant, car il a été simplement oublié.


Ok, j'ai édité ma réponse pour donner une réponse éventuelle pour le "pourquoi manque-t-il?" question.


En attente de la condition entraîne le commutateur de contexte dont vous avez besoin dans votre exemple, il "donne" car ce fil bloque à l'état et n'a pas d'autre choix que de passer à un autre fil runnable.