270 votes

Queue.Queue vs. collections.deque

J'ai besoin d'une file d'attente dans laquelle plusieurs threads peuvent mettre des choses, et dans laquelle plusieurs threads peuvent lire.

Python possède au moins deux classes de files d'attente, Queue.Queue y collections.deque Le premier semble utiliser le second en interne. Les deux prétendent être thread-safe dans la documentation.

Cependant, la documentation sur les files d'attente indique également :

collections.deque est une implémentation alternative implémentation de files d'attente non limitées avec des opérations atomiques rapides de type append() et popleft() rapides et atomiques qui ne ne nécessitent pas de verrouillage.

Ce que je ne comprends pas très bien : Est-ce que cela signifie que deque n'est pas totalement thread-safe après tout ?

Si c'est le cas, je ne comprends peut-être pas bien la différence entre les deux classes. Je peux voir que Queue ajoute une fonctionnalité de blocage. D'un autre côté, elle perd certaines fonctionnalités deque comme le support de l'in-operator.

Accéder directement à l'objet interne deque, c'est

x dans Queue().deque

thread-safe ?

Aussi, pourquoi Queue utilise-t-il un mutex pour ses opérations alors que deque est déjà thread-safe ?

0 votes

RuntimeError: deque mutated during iteration est ce que vous pourriez obtenir est d'utiliser un partagé deque entre plusieurs fils et aucun verrouillage...

8 votes

@toine ça n'a rien à voir avec les fils de discussion. Vous pouvez obtenir cette erreur à chaque fois que vous ajoutez/supprimez à un fichier deque tout en itérant même dans le même thread. La seule raison pour laquelle vous ne pouvez pas obtenir cette erreur à partir de Queue c'est que Queue ne prend pas en charge l'itération.

0 votes

Si vous avez le livre "Effective Python", il y a une très bonne comparaison de Queue vs deque dans un cas d'utilisation multi-thread dans le point 55 ("Use Queue to Coordinate Work Between Threads").

2voto

user83591 Points 3857

deque est à l'abri des fils. Les "opérations qui ne nécessitent pas de verrouillage" signifient que vous n'avez pas besoin d'effectuer le verrouillage vous-même, l'option deque s'en occupe.

En regardant le Queue la source interne deque est appelée self.queue et utilise un mutex pour les accesseurs et les mutations, donc Queue().queue es no à utiliser sans risque pour les fils.

Si vous cherchez un opérateur "in", alors une deque ou une queue n'est peut-être pas la structure de données la plus appropriée pour votre problème.

1 votes

Eh bien, ce que je veux faire, c'est m'assurer qu'aucun doublon n'est ajouté à la file d'attente. N'est-ce pas quelque chose qu'une file d'attente pourrait potentiellement supporter ?

1 votes

Il serait probablement préférable d'avoir un ensemble séparé, et de le mettre à jour lorsque vous ajoutez/supprimez quelque chose de la file d'attente. Ce sera O(log n) plutôt que O(n), mais vous devrez faire attention à garder l'ensemble et la file d'attente synchronisés (c'est-à-dire verrouillés).

0 votes

Un ensemble Python est une table de hachage, donc ce serait O(1). Mais oui, il faudrait toujours faire du verrouillage.

1voto

(il semble que je n'aie pas la réputation de commenter...) Vous devez faire attention aux méthodes du deque que vous utilisez à partir de différents threads.

deque.get() semble être threadsafe, mais j'ai trouvé que faire

for item in a_deque:
   process(item)

peut échouer si un autre thread ajoute des éléments en même temps. J'ai obtenu une RuntimeException qui se plaignait de "deque mutated during iteration".

Vérifiez collectionmodule.c pour voir quelles opérations sont affectées par cette

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X