gpt4 book ai didi

python - pygtk:打印大型输出数据集时使用 io_add_watch block 实现的异步输出

转载 作者:太空宇宙 更新时间:2023-11-04 10:43:10 27 4
gpt4 key购买 nike

我正在使用 python 命令行模拟器编写 GTK+ GUI 程序。我的 python 命令行实现为 gtk.TextView,可用于输出 prints 的结果(并从 TextView 读取命令并 exec 它们,但我不输入部分与问题无关,请勿在此贴出。

我使用以下技术在真实终端和我的 python 命令行之间创建 stdout 流:

r_out, w_out = os.pipe() # create a pipe, cause sys.stdout is unreadable, thus we can't poll it for available output
w_out_stream = os.fdopen(w_out, "w", 0) # open write-end of pipe with 0-length buffer
sys.stdout = w_out_stream # now prints and sys.stdout.writes would go to the pipe
watch = gobject.io_add_watch(r_out, gobject.IO_IN, stdout_callback) # poll the read-end of pipe for data and call stdout_callback

def stdout_callback(stream, condition):
data = os.read(stream, 1) # read the pipe byte-by-byte
iter = textbuf.get_end_iter() # textbuf is buffer of TextView, the GUI widget, I use as python command line
textbuf.insert(iter, data) # output stdout to GUI
sys.__stdout__.write(data) # output stdout to "real" terminal stdout

gtk.main()

这对于小输出来说效果很好。但不幸的是,当输出变得相对较大(如数千字节)时,我的应用程序挂起并且不显示任何输出。

但是,如果我发送一个 SIGINT,我的输出会同时出现在 GUI 和真实终端中。显然,我希望它在没有 SIGINT 的情况下存在。任何想法,是什么导致了这样的障碍?

最佳答案

外部进程在使用 os.read 时阻塞了 UI,您应该使用 glib.spawn_async 生成进程并使用 IOChannel 读取输入,例如:

from gi.repository import Gtk, GLib

class MySpawned(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)

vb = Gtk.VBox(False, 5)
self.tw = Gtk.TextView()
bt = Gtk.Button('Run')
bt.connect('clicked', self.process)

vb.pack_start(self.tw, True, True, 0)
vb.pack_start(bt, False, False, 0)

self.add(vb)
self.set_size_request(200, 300)
self.connect('delete-event', Gtk.main_quit)
self.show_all()

def run(self):
Gtk.main()

def process(self, widget, data=None):
params = ['python', '-h']

def write_to_textview(io, condition):
print condition
if condition is GLib.IO_IN:
line = io.readline()
self.tw.props.buffer.insert_at_cursor(line)
return True
elif condition is GLib.IO_HUP|GLib.IO_IN:
GLib.source_remove(self.source_id)
return False

self.source_id = None

pid, stdin, stdout, stderr = GLib.spawn_async(params,
flags=GLib.SpawnFlags.SEARCH_PATH,
standard_output=True)

io = GLib.IOChannel(stdout)

self.source_id = io.add_watch(GLib.IO_IN|GLib.IO_HUP,
write_to_textview,
priority=GLib.PRIORITY_HIGH)
if __name__ == '__main__':
s = MySpawned()
s.run()

外面有无数个线程告诉你可以使用线程或其他东西,请不要那样做,上面的例子即使在一个很长的过程中也不会阻塞你的 UI,输出将打印在textview,也适用于 Windows(但它会打开一个丑陋的控制台窗口,直到修复 GLib 中的错误)。

关于python - pygtk:打印大型输出数据集时使用 io_add_watch block 实现的异步输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19294929/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com