使用python多处理和诅咒,终止进程似乎会干扰诅咒的显示。
例如,在下面的代码中,为什么终止进程停止诅咒显示文本?(按a后按b)
更确切地说,它似乎不仅字符串"hello“不再显示,而且整个诅咒窗口。
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下运行python3.6。
编辑:
我仍然能够用这个更精简的版本进行复制,这个版本不叫睡眠()。现在只要按下"a“就会触发bug。
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)
发布于 2017-06-21 14:11:13
以下代码起作用:
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()
。好吧,为什么要这么做?为此,我们必须知道制程是如何工作的,以及当您调用Process(target = hang)
时它到底做了什么
分叉 父进程使用os.fork()对Python解释器进行分叉。子进程开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程是有问题的。 仅在Unix上可用。Unix的默认设置。
现在,它告诉我们什么?当您已经创建了一个Processes
屏幕时,您可以在其中创建一个新的curses
。curses.wrapper()是做什么的?
在调用func之前,wrapper()打开cbreak模式,关闭echo,启用终端键盘,并在终端有颜色支持时初始化颜色。在出口(通常或例外情况下),它恢复熟模式,打开回声,并禁用终端键盘。
好的,我们有一个新创建的子进程,它和它的父进程拥有完全相同的资源。当您调用terminate()
来杀死子程序时,它会释放所有资源,包括诅咒包装器。它恢复以前的终端设置,从而破坏您的UI。
要解决这个问题,您必须以不同的方式实现您的程序。预先创建一个新流程,使用IPC与您的流程进行通信,如果需要多个进程使用过程池,如果您有IO绑定任务,则使用穿线或线程池。
发布于 2017-06-21 05:59:31
你可能是在Windows上运行这个吗?该平台上的多处理模块的一个文档要求是,所有顶级代码(在您的情况下是curses.wrapper(display)
)都必须在if __name__ == '__main__':
块中,这样才不会意外地在您生成的进程中执行它。
我认为这里发生的情况是,您生成的进程正在初始化诅咒本身(这涉及适当地设置控制台),然后在控制台终止时恢复到正常状态--从而取消原始程序所做的设置。
https://stackoverflow.com/questions/44677774
复制