函數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