函数glib.spawn_async允许您挂钩在stdout
,stderr
上调用事件的三个回调,以及进程完成时。使用Popen模拟glib.spawn_async ...
如何使用subprocess与线程或asyncio模仿相同的功能?
我更感兴趣的功能,而不是线程/ asynio但包含两个答案将获得赏金。
这里是一个玩具程序,它显示了我想做的事:
import glib
import logging
import os
import gtk
class MySpawn(object):
def __init__(self):
self._logger = logging.getLogger(self.__class__.__name__)
def execute(self, cmd, on_done, on_stdout, on_stderr):
self.pid, self.idin, self.idout, self.iderr = \
glib.spawn_async(cmd,
flags=glib.SPAWN_DO_NOT_REAP_CHILD,
standard_output=True,
standard_error=True)
fout = os.fdopen(self.idout, "r")
ferr = os.fdopen(self.iderr, "r")
glib.child_watch_add(self.pid, on_done)
glib.io_add_watch(fout, glib.IO_IN, on_stdout)
glib.io_add_watch(ferr, glib.IO_IN, on_stderr)
return self.pid
if __name__ == '__main__':
logging.basicConfig(format='%(thread)d %(levelname)s: %(message)s',
level=logging.DEBUG)
cmd = '/usr/bin/git ls-remote https://github.com/DiffSK/configobj'.split()
def on_done(pid, retval, *args):
logging.info("That's all folks!…")
def on_stdout(fobj, cond):
"""This blocks which is fine for this toy example…"""
for line in fobj.readlines():
logging.info(line.strip())
return True
def on_stderr(fobj, cond):
"""This blocks which is fine for this toy example…"""
for line in fobj.readlines():
logging.error(line.strip())
return True
runner = MySpawn()
runner.execute(cmd, on_done, on_stdout, on_stderr)
try:
gtk.main()
except KeyboardInterrupt:
print('')
我要补充的是,由于readlines()
挡住,上面会缓冲所有的输出,并立刻发送。如果这不是您想要的,那么您必须使用readline()
,并确保在命令结束时读完您之前未读过的所有行。
非常感谢您花时间写这个答案。 – Sardathrion
请注意,上面的代码会将'stdout'和'stderr'中的行缓存为readlines()被阻塞。如果您想要更新,请使用'read()',但确保在读取程序线程完成时清空缓冲区。 – Sardathrion