J'utilise Python 2.7.3 et j'ai remarqué le comportement étrange suivant. Considérez cet exemple minimal:
from multiprocessing import Process, Queue
def foo(qin, qout):
while True:
bar = qin.get()
if bar is None:
break
qout.put({'bar': bar})
if __== '__main__':
import sys
qin = Queue()
qout = Queue()
worker = Process(target=foo,args=(qin,qout))
worker.start()
for i in range(100000):
print i
sys.stdout.flush()
qin.put(i**2)
qin.put(None)
worker.join()
Lorsque je boucle plus de 10 000 ou plus, mon script se bloque sur worker.join()
. Cela fonctionne bien lorsque la boucle ne dépasse pas 1 000.
Des idées?
La file d'attente qout
du sous-processus est saturée. Les données que vous avez saisies à partir de foo()
n'entrent pas dans la mémoire tampon des canaux du système d'exploitation utilisés en interne. Le sous-processus bloque ainsi l'ajustement d'une plus grande quantité de données. Mais le processus parent ne lit pas ces données: elles sont simplement bloquées aussi, en attendant la fin du sous-processus. C'est une impasse typique.
Il doit y avoir une limite sur la taille des files d'attente. Considérez la modification suivante:
from multiprocessing import Process, Queue
def foo(qin,qout):
while True:
bar = qin.get()
if bar is None:
break
#qout.put({'bar':bar})
if __name__=='__main__':
import sys
qin=Queue()
qout=Queue() ## POSITION 1
for i in range(100):
#qout=Queue() ## POSITION 2
worker=Process(target=foo,args=(qin,))
worker.start()
for j in range(1000):
x=i*100+j
print x
sys.stdout.flush()
qin.put(x**2)
qin.put(None)
worker.join()
print 'Done!'
Cela fonctionne tel quel (avec la ligne qout.put
mise en commentaire). Si vous essayez de sauvegarder tous les 100 000 résultats, alors la variable qout
devient trop grande: si je décommente la fonction qout.put({'bar':bar})
dans foo
et que la définition de qout
reste dans POSITION 1, le code se bloque. Si, toutefois, je déplace la définition qout
vers POSITION 2, le script se termine.
En bref, vous devez faire attention à ce que ni qin
ni qout
ne deviennent trop grands. (Voir aussi: La taille maximale de la file d'attente de multitraitement est de 32767 )
J'ai eu le même problème sur python3
lorsque j'ai essayé de mettre des chaînes dans une file d'attente d'une taille totale d'environ 5 000 cahrs.
Dans mon projet, il y avait un processus hôte qui établit une file d'attente et démarre un sous-processus, puis se joint. Afrer join
Le processus hôte lit la file d'attente. Lorsque le sous-processus produit trop de données, l'hôte se bloque sur join
. J'ai résolu ce problème en utilisant la fonction suivante pour attendre un sous-processus dans le processus hôte:
def yield_from_process(q, p):
while p.is_alive():
p.join(timeout=1)
while True:
try:
yield q.get(block=False)
except Empty:
break
Je lis de la file dès qu'il se remplit pour qu'il ne devienne jamais très grand
J'essayais de .get()
un travailleur asynchrone après la fermeture du pool
erreur d'indentation en dehors d'un bloc with
j'ai eu ceci
with multiprocessing.Pool() as pool:
async_results = list()
for job in jobs:
async_results.append(
pool.apply_async(
_worker_func,
(job,),
)
)
# wrong
for async_result in async_results:
yield async_result.get()
j'avais besoin de ça
with multiprocessing.Pool() as pool:
async_results = list()
for job in jobs:
async_results.append(
pool.apply_async(
_worker_func,
(job,),
)
)
# right
for async_result in async_results:
yield async_result.get()