Tidak ada jawaban di sini yang menjawab semua kebutuhan saya.
- Tidak ada utas untuk stdout (tidak ada Antrian, dll, juga)
- Non-blocking karena saya perlu memeriksa hal-hal lain yang terjadi
- Gunakan PIPE seperti yang saya perlukan untuk melakukan banyak hal, misalnya stream output, menulis ke file log dan mengembalikan salinan string dari output.
Sedikit latar belakang: Saya menggunakan ThreadPoolExecutor untuk mengelola kumpulan utas, masing-masing meluncurkan subproses dan menjalankannya bersamaan. (Dalam Python2.7, tetapi ini harus bekerja di 3.x yang lebih baru juga). Saya tidak ingin menggunakan utas hanya untuk pengumpulan keluaran karena saya ingin sebanyak mungkin tersedia untuk hal-hal lain (kumpulan 20 proses akan menggunakan 40 utas hanya untuk menjalankan; 1 untuk utas proses dan 1 untuk stdout ... dan lebih banyak jika Anda ingin stderr kurasa)
Saya menelanjangi banyak pengecualian dan semacamnya di sini jadi ini didasarkan pada kode yang bekerja di produksi. Semoga saya tidak merusaknya di copy dan paste. Juga, umpan balik sangat disambut!
import time
import fcntl
import subprocess
import time
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Make stdout non-blocking when using read/readline
proc_stdout = proc.stdout
fl = fcntl.fcntl(proc_stdout, fcntl.F_GETFL)
fcntl.fcntl(proc_stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK)
def handle_stdout(proc_stream, my_buffer, echo_streams=True, log_file=None):
"""A little inline function to handle the stdout business. """
# fcntl makes readline non-blocking so it raises an IOError when empty
try:
for s in iter(proc_stream.readline, ''): # replace '' with b'' for Python 3
my_buffer.append(s)
if echo_streams:
sys.stdout.write(s)
if log_file:
log_file.write(s)
except IOError:
pass
# The main loop while subprocess is running
stdout_parts = []
while proc.poll() is None:
handle_stdout(proc_stdout, stdout_parts)
# ...Check for other things here...
# For example, check a multiprocessor.Value('b') to proc.kill()
time.sleep(0.01)
# Not sure if this is needed, but run it again just to be sure we got it all?
handle_stdout(proc_stdout, stdout_parts)
stdout_str = "".join(stdout_parts) # Just to demo
Saya yakin ada overhead yang ditambahkan di sini tapi itu bukan masalah dalam kasus saya. Secara fungsional itu melakukan apa yang saya butuhkan. Satu-satunya hal yang belum saya pecahkan adalah mengapa ini bekerja dengan sempurna untuk pesan log tetapi saya melihat beberapa print
pesan muncul kemudian dan sekaligus.