python print end 堵塞问题以及如何非堵塞读取subprocess的所有输出做到实时读取
python print end
如下代码:
for i in range(5): time.sleep(1) print(i, end='')
本来想要的效果是每秒输出,但是发现这样写会等所有循环完毕后才会打印,发现需要使用flush参数来立即输出,正确代码如下:
for i in range(5): time.sleep(1) print(i, end='', flush=True)
实时读取subprocess的输出
linux
fcntl库似乎在windows中使用有问题,待找其他库代替,下面代码是基于linux系统
如何实时读取subprocess的输出是一个困扰我很久的问题,最近终于得到了解决,之前是使用subprocess的readline(),但是如果那一行仍未运行完时还是会堵塞,无法做到真正的实时读取,多方调查发现配合fcntl库可以做到,方法如下:
import fcntl import subprocess import os import time p = subprocess.Popen('ping www.baidu.com', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # 避免阻塞 def non_block_read(output): fd = output.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) try: return output.read() except: return "" # 当程序未运行结束时输出 while p.poll() is None: out = non_block_read(p.stdout) if out != None: outstr = out.decode('utf8') print(outstr, end='', flush=True)
windows 可能有用,需验证,在airtest源码中发现
# _*_ coding:UTF-8 _*_ import time from threading import Thread, Event from six.moves import queue from .logger import get_logger LOGGING = get_logger(__name__) class NonBlockingStreamReader: def __init__(self, stream, raise_EOF=False, print_output=True, print_new_line=True, name=None, auto_kill=False): ''' stream: the stream to read from. Usually a process' stdout or stderr. raise_EOF: if True, raise an UnexpectedEndOfStream when stream is EOF before kill print_output: if True, print when readline ''' self._s = stream self._q = queue.Queue() self._lastline = None self.name = name or id(self) def _populateQueue(stream, queue, kill_event): ''' Collect lines from 'stream' and put them in 'queue'. ''' while not kill_event.is_set(): line = stream.readline() if line is not None: queue.put(line) if print_output: # print only new line if print_new_line and line == self._lastline: continue self._lastline = line LOGGING.debug("[%s]%s" % (self.name, repr(line.strip()))) if auto_kill and line == b"": self.kill() elif kill_event.is_set(): break elif raise_EOF: raise UnexpectedEndOfStream else: break self._kill_event = Event() self._t = Thread(target=_populateQueue, args=(self._s, self._q, self._kill_event), name="nbsp_%s"%self.name) self._t.daemon = True self._t.start() # start collecting lines from the stream def readline(self, timeout=None): try: return self._q.get(block=timeout is not None, timeout=timeout) except queue.Empty: return None def read(self, timeout=0): time.sleep(timeout) lines = [] while True: line = self.readline() if line is None: break lines.append(line) return b"".join(lines) def kill(self): self._kill_event.set() class UnexpectedEndOfStream(Exception): pass
例子
nbsp = NonBlockingStreamReader(logcat_proc.stdout, print_output=False) while True: line = nbsp.readline(read_timeout) if line is None: break else: yield line
subprocess 以 ctrl c 方式终止
直接p.kill()方式可能与我们使用命令行时使用ctrl c终止方式不同,比如pytest-html,如果kill()子进程,则报告不会保留,但是以ctrl c方式会保存已测试的结果
import signal p = subprocess... p.send_signal(signal.SIGINT)
喜欢的觉得有用的就点个赞吧,点波关注不迷路呦