Python,多处理和GUI

时间:2014-08-08 13:24:32

标签: python python-2.7 multiprocessing gtk3 pygobject

我有一个带有GUI的程序,需要进行一些多处理。重点是避免冻结GUI,并允许用户在进程运行时使用其他一些按钮。

我希望定义如下方法:

def start_waiting(self, parent, func, args):

    self.window_waiting.show()

    task=Process(func(*args))
    task.start()

    task.join()

    # Some code to execute at the end of the process
    #
    #...

问题是join()无效,我需要它,因为在join()之后执行的代码表明Process何时结束。我将使用该代码更新window_waiting的取消按钮。

然后我想到了另一个避免使用join()的解决方案,我将其替换为:

while task.is_alive():
    time.sleep(0.5)

但它既没有效果,所以我尝试了一个计划C,即创建一个队列:

def worker(input, output):
    for func, args in iter(input.get, 'STOP'):
        result=func(*args)
        output.put(result)


task_queue = Queue()
done_queue = Queue()
task_queue.put(task)

Process(target=worker, args=(task_queue, done_queue)).start()
done_queue.get()

最后一段代码给了我错误:'Pickling an AuthenticationString object is ' TypeError: Pickling an AuthenticationString object is disallowed for security reasons

这导致我multiprocessing.Process subclass using shared queue,但我还没有设法解决问题:/

1 个答案:

答案 0 :(得分:3)

您的第一个示例应如下所示:

def start_waiting(self,parent,func,args):

    ...not relevant code..

    self.window_waiting.show()


    task=Process(target=func, args=args)  # This line is different.
    task.start()


    task.join()

你拥有它的方式,实际上并没有在子进程中执行func;它在父级中执行它,然后将返回值传递给Process。当你调用task.start()时,它可能会立即失败,因为你传递的是func返回的任何内容,而不是函数对象。

请注意,因为您在task.join()内调用了start_waiting,所以它可能会阻止您的GUI,因为start_waitingfunc完成之前不会返回,即使它在儿童过程中运行。它不会阻止的唯一方法是,如果您在GUI的事件循环的单独线程中运行start_waiting。你可能想要更像这样的东西:

def start_waiting(self,parent,func,args):

    ...not relevant code..

    self.window_waiting.show() # You should interact with the GUI in the main thread only.

    self.task = Process(target=func, args=args)  # This line is different.
    self.thrd = threading.Thread(target=self.start_and_wait_for_task)
    self.thrd.start()


def start_and_wait_for_task(self):
    """ This runs in its own thread, so it won't block the GUI. """
    self.task.start()
    self.task.join()
    # If you need to update the GUI at all here, use GLib.idle_add (see https://wiki.gnome.org/Projects/PyGObject/Threading)
    # This is required to safely update the GUI from outside the main thread.