67 votes

Effacer tous les éléments de la file d'attente

Comment puis-je effacer une file d'attente. Par exemple, j'ai des données dans une file d'attente, mais pour une raison quelconque, je n'ai pas besoin des données existantes, et je veux juste effacer la file d'attente.

Y a-t-il un moyen ? Cela fonctionnera-t-il ?

oldQueue = Queue.Queue()

4 votes

Si vous lisez la documentation, elle vous renvoie au module Queue's dernière source et là vous pouvez voir que la représentation interne d'une file FIFO est un deque . Dans la documentation de deque vous remarquerez qu'il y a un clear() ce qui est ce que vous voulez. Vous voudrez probablement aussi entourer cet appel d'une méthode de type q.mutex.acquire() y q.mutex.release() comme le fait le reste du code autour de telles opérations pour le rendre sûr.

116voto

Rob Cowie Points 10471
q = Queue.Queue()
q.queue.clear()

EDIT J'ai omis la question de la sécurité des fils pour des raisons de clarté et de brièveté, mais @Dan D a tout à fait raison, ce qui suit est meilleur.

q = Queue.Queue()
with q.mutex:
    q.queue.clear()

20 votes

Si vous le faites with q.mutex: q.queue.clear() cette opération serait sans risque.

7 votes

@DanD. Corrigez-moi si je me trompe, mais il semble que ce soit en fait un mauvais idée pour moi. .mutex y .queue semble être non documenté et si je ne me trompe pas, l'utilisation de q.mutex serait impasse si vous faites quelque chose comme même q.get_nowait à l'intérieur de son bloc.

1 votes

@Jean-BernardJansen : Il n'est pas automatiquement threadsafe si vous manipulez directement ses composants internes, et q.queue.clear() c'est de bousiller les internes directement.

40voto

V.E.O Points 113

Vous ne pouvez pas vider la file d'attente, car chaque mise en place ajoute également le membre unfinished_tasks. La méthode join dépend de cette valeur. Et all_tasks_done doit aussi être notifié.

q.mutex.acquire()
q.queue.clear()
q.all_tasks_done.notify_all()
q.unfinished_tasks = 0
q.mutex.release()

ou de manière décente, utiliser la paire get et task_done pour effacer les tâches en toute sécurité.

while not q.empty():
    try:
        q.get(False)
    except Empty:
        continue
    q.task_done()

ou simplement créer une nouvelle file d'attente et supprimer l'ancienne.

0 votes

Soyez prudent avec cette méthode également. Le site docs Notez que "si empty() renvoie False, cela ne garantit pas qu'un appel ultérieur à get() ne bloquera pas".

0 votes

@Lack Oui, corrigez-le par un get non bloquant.

2 votes

La deuxième méthode (la méthode "décente") semble être la plus sûre et la plus élégante, et n'utilise que l'API publique et documentée. Quelqu'un peut-il confirmer ?

8voto

Niklas R Points 2269

Cela semble faire l'affaire pour moi. Les commentaires et les ajouts sont les bienvenus au cas où j'aurais oublié quelque chose d'important.

class Queue(queue.Queue):
  '''
  A custom queue subclass that provides a :meth:`clear` method.
  '''

  def clear(self):
    '''
    Clears all items from the queue.
    '''

    with self.mutex:
      unfinished = self.unfinished_tasks - len(self.queue)
      if unfinished <= 0:
        if unfinished < 0:
          raise ValueError('task_done() called too many times')
        self.all_tasks_done.notify_all()
      self.unfinished_tasks = unfinished
      self.queue.clear()
      self.not_full.notify_all()

2 votes

Cela semble être le plus efficace (appel à .clear() ) et la manière correcte (notifications qui incluent les éléments en cours de traitement) de le faire.

0 votes

Une mise en œuvre du multitraitement ressemblerait-elle à cela ?

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