Comment mettre en œuvre une Serrure avec un délai d'attente dans Python 2.7
Est-il un moyen de mettre en œuvre une serrure en Python pour le multithreading fins dont acquire
méthode peut avoir l'arbitraire d'un délai d'attente? Les seules solutions que j'ai trouvé jusqu'à présent l'utilisation d'interrogation, ce qui
- Je trouve inélégant et inefficace
- Ne préserve pas le délimitée d'attente /progrès de garantie de la serrure comme une solution au problème de la section critique
Est-il une meilleure façon de mettre en œuvre cette?
- Vous voudrez peut-être un
threading.Condition
objet (voir la section docs.python.org/library/threading.html#threading.Condition). La Condition de l'objet encapsule une serrure et a unwait
méthode avec un délai d'attente. L'attente est interrompue lorsqu'il arrive à expiration ou lorsquenotify
est appelée sur l'État de l'objet. - Je ne suis pas sûr si c'est une solution à mon problème. Selon les docs et à partir d'un rapide coup d'œil au code source, j'ai pensé que
threading.Condition
juste enroule unethreading.RLock
objet. Avant d'appelerwait
vous devezacquire
le sous-jacent de Verrouillage. En dehors de cela, il semble quewait
est mis en œuvre à l'aide d'une boucle occupée. Suis-je manqué quelque chose?
Vous devez vous connecter pour publier un commentaire.
d'élaborer sur Steven commentaire suggestion:
Choses à remarquer:
threading.Lock()
objets, l'un est interne à lathreading.Condition()
.cond
, c'est lock est acquis; lawait()
opération il se déverrouille, même si, pour n'importe quel nombre de threads peuvent regarder.threading.Condition
peut devenir notifié pour des raisons autres que les délais d'attente, donc vous devez toujours suivre le temps si vous voulez vraiment qu'il expire.waitLock
fonction doit suivre unlock.release()
avec uncond.notify()
alors que les autres threads en attente sont avisés qu'ils doivent réessayer l'acquisition de la serrure. Ce n'est pas indiqué dans l'exemple.TimeoutLock
, de sorte que vous ne comptez pas sur les personnes qui utilisent à la fois la serrure et de la variable de condition correctement. Je me suis un peu amusé mais à l'aide d'une variable de condition (qui est mis en œuvre avec un cadenas) pour mettre en œuvre une serrure. 🙂threading
module lui-même, qui n'a qu'un seul délai capable primitive. depuis une condition n'est pas lui-même quelque chose comme un mutex, il a, pour gérer l'accès pour un mutex.Ma version thread-safe files d'attente http://docs.python.org/2/library/queue.html et leur mettre/trouver les méthodes qui prend en charge timeout.
Jusqu'à présent, fonctionne très bien, mais si quelqu'un peut faire un examen par les pairs sur elle, je serai reconnaissant.
Si quelqu'un a besoin de Python >= 3.2 API:
Je doute que cela peut être fait.
Si vous souhaitez mettre en œuvre ce, sans aucune forme d'interrogation, alors vous avez besoin de l'OS à savoir que le thread est bloqué, et le système d'exploitation doit être conscient de l'attente, afin de débloquer le fil après un certain temps. Pour cela, les besoins de soutien existent déjà dans le système d'exploitation; vous ne pouvez pas mettre en œuvre ce à l'Python niveau.
(Vous pourriez avoir le thread bloqué au niveau de l'OS ou de niveau application, et de disposer d'un mécanisme par lequel il peut être réveillé par un thread différent, au moment approprié, mais alors vous avez besoin que les autres thread pour être efficace interrogation)
En général, vous n'avez pas vraiment délimité en attente/progrès de garantie de la serrure de toute façon, que votre fils devra attendre une surabondance de temps pour un changement de contexte à prendre place à l'avis qu'il a été débloqué. Donc à moins de mettre une limite supérieure sur le montant de contention du PROCESSEUR, vous n'allez pas être en mesure d'utiliser le délai d'attente pour frapper tout dur en temps réel des délais. Mais vous n'avez probablement pas besoin de cela, sinon vous ne rêverait pas de l'aide de verrous mis en œuvre en Python.
En raison de l'Python GIL (Global Interprète de Verrouillage), les bureaux de solutions à base ne sont probablement pas aussi inefficace ou mal illimitée que vous le pensez (en fonction de la façon dont ils sont mis en œuvre) (et en supposant que vous êtes en utilisant soit Disponible ou PyPy).
Il n'y a qu'un seul thread en cours d'exécution à un moment, et par définition, il y a un autre fil que vous souhaitez exécuter (celui qui détient le verrou vous êtes en attente pour). Le GIL est tenu pendant un certain temps par un seul thread à exécuter un tas de bytecode, puis a chuté et acquis de nouveau à donner à quelqu'un d'autre une chance à lui. Donc, si l'bloqué avec timeout thread est juste dans une boucle de vérification de l'heure et de les céder à d'autres threads, il ne fera que réveiller chaque tellement souvent quand il fait le GIL et puis presque immédiatement abandonner de nouveau à quelqu'un d'autre et de le bloquer sur le GIL de nouveau. Parce que ce fil ne pourrait jamais se réveiller quand elle reçoit un tour à la GIL de toute façon, il sera également le faire vérifier dès que possible après l'expiration du délai qu'il serait en mesure de reprendre l'exécution, même si le délai d'attente a été magiquement parfait.
La seule fois où ce sera la cause de beaucoup d'inefficience est si votre fil est bloqué en attente pour le lock-fil de maintien, qui est bloqué en attente pour quelque chose qui ne peut être causé par un autre Python fil (par exemple, bloqué sur IO), et il n'y a pas d'autres exécutable Python threads. Ensuite, votre bureau de vote délai d'attente va vraiment rester là vérification de l'heure à plusieurs reprises, ce qui pourrait être mauvais si vous vous attendez à cette situation de se produire pour de longues périodes de temps.
J'ai pris SingleNegationElimination's réponse et a créé une classe qui peut être utilisé dans un
with
-déclaration de la manière suivante:De cette manière, il ne avertir si le délai d'attente expiré (par défaut=1) et de montrer le propriétaire de la serrure pour l'enquête.
Utiliser de cette façon et qu'une exception sera levée après le délai d'attente:
La
timeout_lock.lock()
instance doit être créé qu'une seule fois et peut être utilisé dans les threads.Ici est la classe ça marche pour moi, mais n'hésitez pas à commenter et à améliorer:
Pour être sûr que le fils n'a vraiment pas intervenir et de ne pas attendre et être averti dès que possible, j'ai écrit un petit multithreading test qui résume les temps nécessaires à l'exécution de tous les threads:
De sortie est:
Bon, c'est déjà mise en œuvre dans python 3.2 ou ci-dessus:
https://docs.python.org/3/library/threading.html
Regardez pour l'enfilage.TIMEOUT_MAX
Mais j'ai amélioré sur le cas de test de plus de frans " version ... mais c'est déjà une perte de temps si vous êtes sur py3.2 ou au-dessus:
Maintenant, dans "Util" le dossier, j'ai "ThreadingUtil.py":