To tylko kwestia czasu. System Windows musi odrodzić 4 procesy w Pool
, które następnie należy uruchomić, zainicjować i przygotować do konsumpcji z poziomu Queue
. W systemie Windows wymaga to każdego procesu podrzędnego, aby ponownie zaimportować moduł __main__
, a instancje Queue
używane wewnętrznie przez Pool
powinny być niepoprawne w każdym potomku. Zajmuje to nietrywialną ilość czasu. Wystarczająco długo, w rzeczywistości, gdy oba twoje połączenia są wykonywane, zanim wszystkie procesy w Pool
są jeszcze uruchomione. Można to zobaczyć, jeśli dodać trochę śledzenia na funkcję prowadzony przez każdego pracownika w 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()))
wyjściowa:
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)>
Jak widać, Worker-1
uruchamia się i konsumuje zarówno zadania przed pracownikami 2-4 nigdy nie próbuj konsumować z poziomu Queue
. Jeśli dodasz sleep
połączenia po instancję Pool
w głównym procesie, ale przed wywołaniem map_async
, zobaczysz różne procesy obsłużyć każde żądanie:
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)>
(Należy pamiętać, że dodatkowe "getting
/"got"
wypowiedzi widać są strażnicy są wysyłani do każdego procesu, aby je zamknąć w sposób gratyfikacyjny).
Używając języka Python 3.x w systemie Linux, mogę odtworzyć to zachowanie, używając kontekstów 'spawn'
i 'forkserver'
, ale nie 'fork'
. Prawdopodobnie dlatego, że rozwidlenie procesów potomnych jest znacznie szybsze niż utworzenie ich i ponowne zaimportowanie __main__
.
Używasz Windows? – dano
@ dano-yes ....., – user1050619