Chcę uruchamiać wiele procesów równolegle ze zdolnością do przyjmowania stdout w dowolnym momencie. Jak mam to zrobić? Czy muszę uruchomić wątek dla każdego wywołania subprocess.Popen()
, co?Podproces Pythona równolegle
Odpowiedz
Możesz to zrobić w jednym wątku.
Załóżmy, że masz skrypt, który drukuje wiersze losowo razy:
#!/usr/bin/env python
#file: child.py
import os
import random
import sys
import time
for i in range(10):
print("%2d %s %s" % (int(sys.argv[1]), os.getpid(), i))
sys.stdout.flush()
time.sleep(random.random())
i chcesz zbierać wyjścia, jak tylko stanie się ona dostępna, można użyć select
na systemach POSIX jak @zigg suggested:
#!/usr/bin/env python
from __future__ import print_function
from select import select
from subprocess import Popen, PIPE
# start several subprocesses
processes = [Popen(['./child.py', str(i)], stdout=PIPE,
bufsize=1, close_fds=True,
universal_newlines=True)
for i in range(5)]
# read output
timeout = 0.1 # seconds
while processes:
# remove finished processes from the list (O(N**2))
for p in processes[:]:
if p.poll() is not None: # process ended
print(p.stdout.read(), end='') # read the rest
p.stdout.close()
processes.remove(p)
# wait until there is something to read
rlist = select([p.stdout for p in processes], [],[], timeout)[0]
# read a line from each process that has output ready
for f in rlist:
print(f.readline(), end='') #NOTE: it can block
bardziej przenośnym rozwiązaniem (które powinny działać w systemie Windows, Linux, OSX) mogą wykorzystywać wątki reader dla każdego procesu, zobacz Non-blocking read on a subprocess.PIPE in python.
Oto os.pipe()
-na rozwiązanie, które działa na systemach Unix i Windows:
#!/usr/bin/env python
from __future__ import print_function
import io
import os
import sys
from subprocess import Popen
ON_POSIX = 'posix' in sys.builtin_module_names
# create a pipe to get data
input_fd, output_fd = os.pipe()
# start several subprocesses
processes = [Popen([sys.executable, 'child.py', str(i)], stdout=output_fd,
close_fds=ON_POSIX) # close input_fd in children
for i in range(5)]
os.close(output_fd) # close unused end of the pipe
# read output line by line as soon as it is available
with io.open(input_fd, 'r', buffering=1) as file:
for line in file:
print(line, end='')
#
for p in processes:
p.wait()
Wygląda na to, że w ostatnim rozwiązaniu multipleksowane są wszystkie wyjściowe stdoutów dla dzieci do pojedynczego fd (output_fd). Co jeśli 2 dzieci wydrukują w tym samym czasie, czy to nie zepsuje danych wyjściowych (np. "AAA \ n" + "BBB \ n" -> "ABBB \ nAA \ n") – dan3
@ dan3: To jest ważny problem . 'write's, które są mniejsze niż' PIPE_BUF' bajty są atomowe. W przeciwnym razie dane z wielu procesów mogą być przeplatane. POSIX wymaga co najmniej 512 bajtów. W systemie Linux wartość "PIPE_BUF" wynosi 4096 bajtów. – jfs
Oto podobne pytanie, które napisałem niedawno tutaj, http://stackoverflow.com/questions/36624056/running-a-secondary-script-in-a-new-minminal byłoby fantastyczne, gdybyś mógł pomóc, w każdym razie dzięki . –
Nie trzeba uruchamiać wątku dla każdego procesu. Możesz przeglądać strumienie stdout
dla każdego procesu bez blokowania ich i czytać tylko z nich, jeśli mają dane do odczytania.
Musisz być ostrożny, aby nie zablokować ich przypadkowo, jeśli nie masz na to ochoty.
Wykonuję 'p = podproces.open (...)', a następnie 'print p.communicate() [0] 'kilka razy. Ale 'communic()' czeka przed zakończeniem procesu. – sashab
Tak, dlatego nie można użyć opcji 'communicate() ', jeśli chcesz użyć pojedynczego wątku. Istnieją inne sposoby uzyskiwania stdoutów oprócz 'komunikacji()'. – Amber
Prawdopodobnie musisz zajrzeć do modułu [select] (http://docs.python.org/library/select.html), aby poczekać na wiele podprocesów naraz. – zigg
Można również zbierać stdout z wielu podprocesów jednocześnie stosując twisted
:
#!/usr/bin/env python
import sys
from twisted.internet import protocol, reactor
class ProcessProtocol(protocol.ProcessProtocol):
def outReceived(self, data):
print data, # received chunk of stdout from child
def processEnded(self, status):
global nprocesses
nprocesses -= 1
if nprocesses == 0: # all processes ended
reactor.stop()
# start subprocesses
nprocesses = 5
for _ in xrange(nprocesses):
reactor.spawnProcess(ProcessProtocol(), sys.executable,
args=[sys.executable, 'child.py'],
usePTY=True) # can change how child buffers stdout
reactor.run()
Zobacz Using Processes in Twisted.
- 1. Python: wykonać koci podproces równolegle
- 2. argumenty Pythona podproces
- 3. Pythona podproces .check_call vs .check_output
- 4. Podproces Pythona Popen.communicate() jest odpowiednikiem Popen.stdout.read()?
- 5. rurociągów w powłoce poprzez moduł Pythona podproces
- 6. Podproces Pythona check_output dużo wolniej niż zadzwoń
- 7. wykonać polecenie cat w podproces, popen() Pythona
- 8. Python: Jak uruchomić funkcje Pythona równolegle?
- 9. Podproces plik błąd
- 10. Python podproces Pomoc
- 11. jednostka testująca funkcję Pythona, która wywołuje podproces vim
- 12. Podproces Pythona - Przekieruj stdout/err na dwa miejsca
- 13. Jak rozwiązać podproces Pythona uruchomiony z powłoki = True
- 14. Podproces Pythona zwraca niezerowy status wyjścia tylko w cronie
- 15. Python podproces bash: nawiasy klamrowe
- 16. Podproces Python wprowadza spacje
- 17. Czy możliwe jest równoległe testowanie Pythona równolegle, jak nos?
- 18. wykonywania zadań równolegle pytona
- 19. Podproces Pythona.Popen z wątku
- 20. Podproces FFMPEG i Pythons
- 21. Python: podproces z innego katalogu roboczego
- 22. Jak ukryć wyjście podproces w Pythonie 2.7
- 23. Zabijanie podproces tym jego dzieci z pytona
- 24. Jak korzystać podproces POPEN Python
- 25. pragmy OMP równolegle do porównaniu pragmy OMP równolegle
- 26. równolegle parMap i strategie
- 27. Async czekać i równolegle
- 28. Równolegle konfiguracja parLapply
- 29. RxJava Fetching Observables Równolegle
- 30. Wiosna @Scheduler równolegle działa
możliwy duplikat [jak uruchomić kilka plików wykonywalnych za pomocą Pythona?] (Http://stackoverflow.com/questions/9724499/how-to-run-several-executable-using-python) –
powiązane: Oto jak to zrobić [ uruchamiać wiele poleceń powłoki (i opcjonalnie przechwytywać ich dane wyjściowe) jednocześnie) (http://stackoverflow.com/a/23616229/4279) – jfs