web-dev-qa-db-fra.com

Erreur de canal cassé avec le multitraitement.

En python2.7, le multiprocessing.Queue génère une erreur cassée lorsqu'il est initialisé depuis l'intérieur d'une fonction. Je fournis un exemple minimal qui reproduit le problème.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import multiprocessing

def main():
    q = multiprocessing.Queue()
    for i in range(10):
        q.put(i)

if __name__ == "__main__":
    main()

jette l'erreur de tuyau cassée ci-dessous

Traceback (most recent call last):
File "/usr/lib64/python2.7/multiprocessing/queues.py", line 268, in _feed
send(obj)
IOError: [Errno 32] Broken pipe

Process finished with exit code 0

Je n'arrive pas à déchiffrer pourquoi. Il serait certainement étrange que nous ne puissions pas remplir les objets Queue depuis l'intérieur d'une fonction.

11
hAcKnRoCk

Ce qui se passe ici, c'est que lorsque vous appelez main(), il crée le Queue, y met 10 objets et termine la fonction, ramassant toutes ses variables et objets internes, y compris le Queue. MAIS vous obtenez cette erreur car vous essayez toujours d'envoyer le dernier numéro dans le Queue.

de la documentation documentation :

"Lorsqu'un processus place pour la première fois un élément dans la file d'attente, un thread d'alimentation est démarré et transfère les objets d'un tampon dans le tuyau."

Comme la put() est faite dans un autre Thread, elle ne bloque pas l'exécution du script, et permet de terminer la fonction main() avant de terminer les opérations de la file d'attente.

Essaye ça :

#!/usr/bin/python
# -*- coding: utf-8 -*-

import multiprocessing
import time
def main():
    q = multiprocessing.Queue()
    for i in range(10):
        print i
        q.put(i)
    time.sleep(0.1) # Just enough to let the Queue finish

if __name__ == "__main__":
    main()

Il devrait y avoir un moyen de join l'exécution de la file d'attente ou du bloc jusqu'à ce que l'objet soit placé dans le Queue, vous devriez jeter un oeil dans la documentation.

9
CoMartel

Lorsque vous lancez Queue.put (), le thread implicite est démarré pour fournir des données à une file d'attente. Pendant ce temps, l'application principale est terminée et il n'y a pas de station de fin pour les données (l'objet de file d'attente est récupéré).

J'essaierais ceci:

from multiprocessing import Queue

def main():
    q = Queue()
    for i in range(10):
        print i
        q.put(i)
    q.close()
    q.join_thread()

if __name__ == "__main__":
    main()

join_thread() garantit que toutes les données du tampon ont été vidées. close() doit être appelée avant join_thread()

15
Peter Svac

Avec un retard en utilisant time.sleep(0.1) comme suggéré par @HarryPotFleur, ce problème est résolu. Cependant, j'ai testé le code avec python3 et le problème de canal cassé ne se produit pas du tout en python3. Je pense que cela a été signalé comme un bug et corrigé plus tard.

0
hAcKnRoCk