Я наконец получил рабочее решение;ключевая часть информации, которую я пропустил, была thread.daemon = True
, на которую @augurar указал в своем ответе.
Установка thread.daemon = True
позволяет завершать поток при завершении основного процесса;поэтому разблокирование моего использования подпотока для мониторинга readline()
.
Вот пример реализации моего решения;Я использовал объект Queue()
для передачи строк в основной процесс, и я реализовал 3-секундный таймер для случаев, подобных исходной проблеме, которую я пытался решить, когда подпроцесс завершился и завершился, но readline () зависает для некоторыхпричина.
Это также помогает избежать состояния гонки, между которым вещь заканчивается первым.
Это работает как для Python 2, так и для 3.
import sys
import threading
import subprocess
from datetime import datetime
try:
import queue
except:
import Queue as queue # Python 2 compatibility
def _monitor_readline(process, q):
while True:
bail = True
if process.poll() is None:
bail = False
out = ""
if sys.version_info[0] >= 3:
out = process.stdout.readline().decode('utf-8')
else:
out = process.stdout.readline()
q.put(out)
if q.empty() and bail:
break
def bash(cmd):
# Kick off the command
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
# Create the queue instance
q = queue.Queue()
# Kick off the monitoring thread
thread = threading.Thread(target=_monitor_readline, args=(process, q))
thread.daemon = True
thread.start()
start = datetime.now()
while True:
bail = True
if process.poll() is None:
bail = False
# Re-set the thread timer
start = datetime.now()
out = ""
while not q.empty():
out += q.get()
if out:
print(out)
# In the case where the thread is still alive and reading, and
# the process has exited and finished, give it up to 3 seconds
# to finish reading
if bail and thread.is_alive() and (datetime.now() - start).total_seconds() < 3:
bail = False
if bail:
break
# To demonstrate output in realtime, sleep is called in between these echos
bash("echo lol;sleep 2;echo bbq")