使用python多处理和curses,似乎终止进程会干扰curses显示 例如,在以下代码中,为什么终止进程会阻止curses显示文本? (按a后按b) 更确切地说,似乎不仅是字符串"你好"不再显示,而是整个curses窗口。
import curses
from multiprocessing import Process
from time import sleep
def display(stdscr):
stdscr.clear()
curses.newwin(0,0)
stdscr.timeout(500)
p = None
while True:
stdscr.addstr(1, 1, "hello")
stdscr.refresh()
key = stdscr.getch()
if key == ord('a') and not p:
p = Process(target = hang)
p.start()
elif key == ord('b') and p:
p.terminate()
def hang():
sleep(100)
if __name__ == '__main__':
curses.wrapper(display)
我在GNU / Linux下运行python 3.6。
编辑:
我仍然可以使用这个没有调用sleep()的更简化的版本来重现。现在只需按下" a"触发了这个错误。
import curses
from multiprocessing import Process
def display(stdscr):
stdscr.clear()
curses.newwin(0,0)
stdscr.timeout(500)
p = None
while True:
stdscr.addstr(1, 1, "hello")
stdscr.refresh()
key = stdscr.getch()
if key == ord('a') and not p:
p = Process(target = hang)
p.start()
p.terminate()
def hang():
while True:
temp = 1 + 1
if __name__ == '__main__':
curses.wrapper(display)
答案 0 :(得分:1)
你是在Windows上运行吗?该平台上多处理模块的一个记录要求是,所有顶级代码(在您的情况下为curses.wrapper(display)
)必须位于if __name__ == '__main__':
块内,因此不会意外在你的衍生过程中执行。
我认为这里发生的事情是你的衍生进程正在初始化curses本身(这涉及适当地设置控制台),然后在终止时将控制台恢复正常 - 从而撤消原始设置所做的设置程序
答案 1 :(得分:1)
以下代码有效:
import curses
from multiprocessing import Process
p = None
def display(stdscr):
stdscr.clear()
curses.newwin(0,0)
stdscr.timeout(500)
while True:
stdscr.addstr(1, 1, "hello")
stdscr.refresh()
key = stdscr.getch()
if key == ord('a') and not p:
p.start()
p.terminate()
def hang():
while True:
temp = 1 + 1
if __name__ == '__main__':
p = Process(target = hang)
curses.wrapper(display)
在使用Process
初始化UI之前,我创建了一个新的curses.wrapper()
。好的,为什么这个有效?为此,我们必须知道Proccess的工作原理以及拨打Process(target = hang)
时的确切行为:
叉
父进程使用os.fork()来分叉Python解释器。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程存在问题。
仅适用于Unix。 Unix上的默认值。
现在,它告诉我们什么?您在创建Processes
屏幕时创建新curses
的位置。 curses.wrapper()做了什么?
在调用func之前,wrapper()打开cbreak模式,关闭echo,启用终端键盘,并在终端有颜色支持时初始化颜色。退出时(无论是正常还是异常),它将恢复烹饪模式,打开回声,并禁用终端键盘。
好的,我们有一个新创建的子进程,它具有与其父进程完全相同的资源。当你调用terminate()
来杀死孩子时,它会释放所有资源,包括curses包装器。它会恢复以前的终端设置,因此会破坏您的用户界面。
要解决此问题,您必须以不同方式实施您的程序。事先创建一个新流程,使用IPC与流程进行通信,如果需要多个流程,请使用Process Pools,如果您有IO绑定任务,请使用Threading或Thread Pools。