繁体   English   中英

终止进程会破坏python curses

[英]Terminating a process breaks python curses

使用python多重处理和curses,似乎终止进程会干扰curses显示。
例如,在下面的代码中,为什么终止进程会阻止curses显示文本? (按a之后按b)
更准确地说,似乎不仅不再显示字符串“ hello”,而且还显示了整个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)

您是否正在Windows上运行此程序? 该平台上的多处理模块的文档要求之一是,所有顶级代码(在您的情况下为curses.wrapper(display) )都必须位于if __name__ == '__main__':块内,因此它不是“不会在您生成的过程中意外执行。

我认为这里发生的情况是,您生成的过程本身正在初始化curses(这涉及适当地设置控制台),然后在终止时将控制台恢复为正常状态,从而撤消了原始程序所做的设置。

以下代码有效:

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)

在使用curses.wrapper()初始化UI之前,我创建了一个新Process 好吧,为什么这行得通? 为此,我们必须知道Proccess的工作方式以及调用Process(target = hang)时的确切作用:

叉子

父进程使用os.fork()派生Python解释器。 子进程开始时实际上与父进程相同。 父进程的所有资源均由子进程继承。 请注意,安全地分叉多线程进程是有问题的。

仅在Unix上可用。 Unix上的默认值。

现在,它告诉我们什么? 当您已经创建了curses屏幕时,您将在其中创建新的Processes curses.wrapper()有什么作用?

在调用func之前,wrapper()打开cbreak模式,关闭echo,启用终端键盘,并在终端支持颜色的情况下初始化颜色。 退出时(无论是正常还是异常),它都将恢复烹饪模式,打开回显,并禁用终端键盘。

好的,我们有一个新创建的子进程,它的资源与其父进程完全相同。 当您调用terminate()杀死孩子时,它将释放所有资源,包括curses包装器。 它会还原以前的终端设置,因此会破坏用户界面。

要解决此问题,您必须以不同的方式实现您的程序。 事先创建一个新进程,使用IPC与您的进程进行通信,如果需要多个进程,请使用进程池 ,如果有IO绑定的任务,请使用线程线程池

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM