wca*_*art 3 python curses multithreading
我正在尝试在长期运行的函数的进度条下方实现一个简单的微调器(使用根据此答案改编的代码)。
[######## ] x%
/ Compressing filename
Run Code Online (Sandbox Code Playgroud)
我让压缩和进度条在脚本的主线程中运行,而旋转器在另一个线程中运行,因此它实际上可以在压缩发生时旋转。但是,我curses同时使用进度条和微调器,并且都使用curses.refresh()
有时终端会随机输出乱码,我不知道为什么。我认为这是由于旋转器的多线程性质造成的,因为当我禁用旋转器时,问题就消失了。
这是旋转器的伪代码:
def start(self):
self.busy = True
global stdscr
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
threading.Thread(target=self.spinner_task).start()
def spinner_task(self):
while self.busy:
stdscr.addstr(1, 0, next(self.spinner_generator))
time.sleep(self.delay)
stdscr.refresh()
Run Code Online (Sandbox Code Playgroud)
这是进度条的伪代码:
progress_bar = "\r[{}] {:.0f}%".format("#" * block + " " * (bar_length - block), round(progress * 100, 0))
progress_file = " {} {}".format(s, filename)
stdscr.clrtoeol()
stdscr.addstr(1, 1, " ")
stdscr.clrtoeol()
stdscr.addstr(0, 0, progress_bar)
stdscr.addstr(1, 1, progress_file)
stdscr.refresh()
Run Code Online (Sandbox Code Playgroud)
并从类似的地方打电话main():
spinner.start()
for each file:
update_progress_bar
compress(file)
spinner.stop()
Run Code Online (Sandbox Code Playgroud)
为什么输出有时会被损坏?是因为单独的线程吗?如果是这样,有什么更好的设计方法建议吗?
cursesPython 模块依赖的库不是curses线程安全的。
ncurses有一个curs_threads功能,显然从大约十年前的 5.7 版本就已经存在了。但它需要改变一些 API 调用的方式,并链接到-lncursest,这仍然不是微不足道的,并且 \xe2\x80\xa6 几乎没有人使用过它。
据我所知,没有标准安装程序或发行版包会构建 Pythoncurses来链接ncursest\xe2\x80\x94,即使发行版ncursest首先包含(它们通常不会)。即使他们这样做了,也没有线程安全函数的绑定,因此您仍然无法安全地访问诸如设置制表符大小之类的内容。
根据我的(可能过时的,也可能是平台限制的)经验,你仍然可以逃脱惩罚,但你需要:
\n\ngetch和 之类的东西getmouse。Lock,然后确保每批更新都以 结尾refresh,并且整批更新都在锁内。curs_threads,例如,不要更改 escdelay 或 tabsize。但执行此操作的安全方法是执行与tkinter或其他不理解线程的 GUI 库相同的操作。它并不完全相同,但想法相似。最简单的版本是:
\n\nqueue.Queue,以便您的后台线程可以请求curses运行命令。(你不需要任何复杂的东西来表示“命令”,它只是一个(func, *args)元组,因为 Python。)如果您的后台线程需要调用返回值的函数,显然您需要使这稍微复杂一些。你可以看看如何multiprocessing.dummy.AsyncResult和concurrent.futures.Future工作。或者你甚至可以Future为了自己的目的而偷窃。但您可能不需要任何那么复杂的东西。
如果您正在循环输入,您可能还希望主线程执行此操作(这意味着选择“帧速率”并在等待队列和输入之间交替,并超时)并分派它,即使您总是分派到同一个线程。
\n\n您甚至可以编写一个mtTkinter-style 包装器来重现curses接口(甚至猴子补丁curses模块),但用将函数和参数放入队列的调用来替换每个函数。但我不确定这是否值得付出努力。
| 归档时间: |
|
| 查看次数: |
3130 次 |
| 最近记录: |