Si tratta solo di tempi. Windows ha bisogno di generare 4 processi nel Pool
, che devono quindi essere avviati, inizializzati e preparati a consumare dallo Queue
. Su Windows, questo richiede che ogni processo figlio reimportazione il modulo __main__
e che le istanze utilizzate internamente dallo Pool
siano deselezionate in ciascun figlio. Questo richiede una quantità di tempo non trascurabile. Abbastanza a lungo, infatti, quando tutte e due le vostre chiamate-vengono eseguite prima che tutti i processi nello Pool
siano ancora attivi e in esecuzione. Si può vedere questo se si aggiunge un po 'di tracciare la funzione gestita da ciascun lavoratore nel Pool
:
while maxtasks is None or (maxtasks and completed < maxtasks):
try:
print("getting {}".format(current_process()))
task = get() # This is getting the task from the parent process
print("got {}".format(current_process()))
uscita:
getting <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
process id = 5145
getting <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
process id = 5145
getting <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
result = [121]
result1 = [100]
getting <ForkServerProcess(ForkServerPoolWorker-2, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-3, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-4, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
Come si può vedere, Worker-1
avvia e consuma entrambe le attività prima che i lavoratori 2-4 mai provare a consumare dal Queue
. Se si aggiunge una chiamata sleep
dopo si crea un'istanza della Pool
nel processo principale, ma prima di chiamare map_async
, vedrete diversi processi gestire ogni richiesta:
getting <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-2, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-3, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-4, started daemon)>
# <sleeping here>
got <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
process id = 5183
got <ForkServerProcess(ForkServerPoolWorker-2, started daemon)>
process id = 5184
getting <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
getting <ForkServerProcess(ForkServerPoolWorker-2, started daemon)>
result = [121]
result1 = [100]
got <ForkServerProcess(ForkServerPoolWorker-3, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-4, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-1, started daemon)>
got <ForkServerProcess(ForkServerPoolWorker-2, started daemon)>
(Si noti che l'extra "getting
/"got"
affermazioni che vedete siano sentinelle inviate ad ogni processo per chiuderle con grazia).
Utilizzando Python 3.x su Linux, sono in grado di riprodurre questo comportamento utilizzando i contesti 'spawn'
e 'forkserver'
, ma non 'fork'
. Presumibilmente perché la forking dei processi figlio è molto più veloce che generarli e fare una reimportazione di __main__
.
Si sta utilizzando Windows? – dano
@ dano-sì ....., – user1050619