wxPython非阻塞GUI线程和多处理?

时间:2012-06-07 16:01:39

标签: python multithreading wxpython multiprocessing nonblocking

Python 2.7.3 x64 wxPython 2.8 x64

已经阅读了很多关于python线程和多处理的内容,特别是Doug Hellmann撰写的一些文章,这些文章有很大的帮助。但是,我对一件事感到困惑......

我认为 Python多处理模块或多或少是线程模块的直接替代品,除了args必须是可选择的,但我发现为了不阻止我的GUI,我必须首先使用threading.Thread创建一个新线程,然后使用multiprocessing.Process在该线程中进行多进程。这很有效,而且效果很好,但对我来说似乎有点笨拙。

如果我尝试在没有第一次线程的情况下直接进行多处理,那么我的GUI仍会阻塞,直到多处理作业完成。这是按设计工作,还是我遗漏了多处理模块的基本原理?

如果需要示例,我可以提供。

谢谢,

-RMWChaos

要求提供一个例子......

假设onProcess()由GUI中的按钮触发,这会阻止GUI ...

import time
import multiprocessing as mp

def myWorker(a, b):
    time.sleep(0.1)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    jobs = mp.cpu_count() * 2
    a = 5
    b = 10

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()

虽然这不是......

import time
import multiprocessing as mp
import threading as th

def myWorker(a, b):
    time.sleep(0.1)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    a = 5
    b = 10
    th.Thread(target = myThread, args = [a, b,]).start()

def myThread(a, b):
    jobs = mp.cpu_count() * 2

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()

2 个答案:

答案 0 :(得分:5)

多线程和多处理从根本上是不同的。

线程主要用于i / o。当你创建一个新线程时,它包含在与你生成线程的程序相同的进程中。这意味着它与程序共享内存空间,但它们(程序和线程)不能并行运行(也可以查找GIL)。

另一方面,多处理会在操作系统级别上产生一个新进程。这个新进程可以与预先存在的进程并行运行,但它不会与生成它的程序共享内存空间。当您想要加速的代码不是i / o相关但是实际的处理器密集型计算时,这更有用。

对于一个gui,你大多数时候都想对gui的不同部分使用线程,这样在gui的一部分中运行某些东西并不会锁定整个gui,直到处理结束。

没有代码很难说,但我相信你不应该特别需要在新线程中生成一个进程,而只是让该线程处理这个进程。但是,如果该线程需要处理密集的计算类型的处理而不是大量的i / o,那么您可能希望启动一个处理它的过程。

我相信你的大多数问题都在于误解多处理与多线程。

答案 1 :(得分:1)

我尝试在以下测试程序中运行您的代码,并且多处理工作正常,没有任何阻止:

import time
import multiprocessing as mp
import wx


def myWorker(a, b):
    time.sleep(10)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    jobs = mp.cpu_count() * 2
    a = 5
    b = 10

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()

def onGUI(event):
    print 'GUI is not blocked'

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
       wx.Frame.__init__(self, parent, id, title)
       buttons = []
       panel = wx.Panel(self, wx.ID_ANY)
       sizer = wx.BoxSizer(wx.VERTICAL)
       gui_proc_btn = wx.Button(panel, wx.ID_ANY, 'GUI Process')
       other_proc_btn = wx.Button(panel, wx.ID_ANY, 'Other process')

       gui_proc_btn.Bind(wx.EVT_BUTTON, onGUI)
       sizer.Add(gui_proc_btn, 0, wx.ALL, 5)
       other_proc_btn.Bind(wx.EVT_BUTTON, onProcess)
       sizer.Add(other_proc_btn, 0, wx.ALL, 5)
       panel.SetSizer(sizer)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test.py')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

if __name__ == '__main__':

    app = MyApp(0)
    app.MainLoop()

从命令行运行此命令,按第二个按钮(这会在您的功能上使用multiprocessing,我增加了睡眠时间),然后按第一个按钮。 您应该注意到按下第一个按钮时会产生输出,因此程序不会被阻止。