在Python中对子进程进行非阻塞读取 您所在的位置:网站首页 python读取fifo非阻塞 在Python中对子进程进行非阻塞读取

在Python中对子进程进行非阻塞读取

2024-06-03 00:44| 来源: 网络整理| 查看: 265

My problem is a bit different as I wanted to collect both stdout and stderr from a running process, but ultimately the same since I wanted to render the output in a widget as its generated.

I did not want to resort to many of the proposed workarounds using Queues or additional Threads as they should not be necessary to perform such a common task as running another script and collecting its output.

After reading the proposed solutions and python docs I resolved my issue with the implementation below. Yes it only works for POSIX as I’m using the select function call.

I agree that the docs are confusing and the implementation is awkward for such a common scripting task. I believe that older versions of python have different defaults for Popen and different explanations so that created a lot of confusion. This seems to work well for both Python 2.7.12 and 3.5.2.

The key was to set bufsize=1 for line buffering and then universal_newlines=True to process as a text file instead of a binary which seems to become the default when setting bufsize=1.

class workerThread(QThread): def __init__(self, cmd): QThread.__init__(self) self.cmd = cmd self.result = None ## return code self.error = None ## flag indicates an error self.errorstr = "" ## info message about the error def __del__(self): self.wait() DEBUG("Thread removed") def run(self): cmd_list = self.cmd.split(" ") try: cmd = subprocess.Popen(cmd_list, bufsize=1, stdin=None , universal_newlines=True , stderr=subprocess.PIPE , stdout=subprocess.PIPE) except OSError: self.error = 1 self.errorstr = "Failed to execute " + self.cmd ERROR(self.errorstr) finally: VERBOSE("task started...") import select while True: try: r,w,x = select.select([cmd.stdout, cmd.stderr],[],[]) if cmd.stderr in r: line = cmd.stderr.readline() if line != "": line = line.strip() self.emit(SIGNAL("update_error(QString)"), line) if cmd.stdout in r: line = cmd.stdout.readline() if line == "": break line = line.strip() self.emit(SIGNAL("update_output(QString)"), line) except IOError: pass cmd.wait() self.result = cmd.returncode if self.result < 0: self.error = 1 self.errorstr = "Task terminated by signal " + str(self.result) ERROR(self.errorstr) return if self.result: self.error = 1 self.errorstr = "exit code " + str(self.result) ERROR(self.errorstr) return return

ERROR, DEBUG and VERBOSE are simply macros that print output to the terminal.

This solution is IMHO 99.99% effective as it still uses the blocking readline function, so we assume the sub process is nice and outputs complete lines.

I welcome feedback to improve the solution as I am still new to Python.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有