简体   繁体   English

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

[英]wxPython non-blocking GUI threading AND multiprocessing?

Python 2.7.3 x64 wxPython 2.8 x64 Python 2.7.3 x64 wxPython 2.8 x64

Been reading quite a bit on python threading and multiprocessing, particularly some articles by Doug Hellmann, which have helped tremendously. 一直在阅读有关python线程和多处理的文章,特别是Doug Hellmann的一些文章,这些文章提供了极大的帮助。 However, I'm confused about one thing... 但是,我对一件事感到困惑...

I thought the Python multiprocessing module was more-or-less a drop-in replacement for the threading module, excepting that args must be picklable, but I'm finding that in order not to block my GUI, I must first create a new thread with threading.Thread then multiprocess within that thread with multiprocessing.Process. 以为 Python多处理模块或多或少是线程模块的替代品,除了args必须是可腌制的,但我发现为了不阻塞我的GUI,我必须首先创建一个新线程然后使用threading.Thread,然后在该线程中使用multiprocessing.Process进行多进程。 This works, and works well, but it seems a bit kludgey to me. 这行得通,而且效果很好,但是对我来说似乎有点不合时宜。

If I try to directly multiprocess without first threading, then my GUI still blocks until the multiprocessing job is done. 如果我尝试不先执行线程就直接进行多进程处理,那么我的GUI仍会阻塞,直到完成多处理作业为止。 Is that working as designed, or am I missing something fundamental about the multiprocessing module? 这是按设计工作的,还是我缺少有关多处理模块的基本知识?

If examples are needed, I can provide them. 如果需要示例,我可以提供它们。

Thanks, 谢谢,

-RMWChaos -RMWChaos

An example was requested... 请求一个例子...

Assuming that onProcess() is triggered by a button in the GUI, this blocks the GUI... 假设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()

While this doesn't... 虽然这不...

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()

Multi-threading and multi-processing are fundamentally different. 多线程和多处理本质上是不同的。

Threads are used for i/o for the most part. 线程大部分用于I / O。 When you make a new thread it is contained within the same process as the program you spawned the thread from. 当您创建新线程时,它与从中生成线程的程序所包含的进程相同。 What that means is that it shares memory space with the program, but they (the program and the thread) cannot run in parallel (also look up GIL). 这意味着它与程序共享内存空间,但是它们(程序和线程)不能并行运行(也要查找GIL)。

Multi-processing on the other hand spawns a new process on the OS level. 另一方面,多处理在OS级别上产生了一个新进程。 This new process can run in parallel with the pre-existing process, but it does not share memory space with the program that spawned it. 此新进程可以与先前存在的进程并行运行,但是不会与产生该进程的程序共享内存空间。 This is more useful when the code you want to speed up is not i/o related but actual processor intensive computation. 当您要加速的代码与I / O不相关,而与实际的处理器密集型计算有关时,此功能将更为有用。

For a gui, you mostly want to use threading for different parts of the gui so that running something in one part of the gui does not lock up your entire gui until that handling ends. 对于gui,您通常想对gui的不同部分使用线程,以便在gui的一部分中运行某些操作不会锁定整个gui,直到处理结束为止。

Without code it is hard to tell, but I believe you should not particularly need to spawn a process within the new thread, but instead just have that thread handle the processing. 没有代码很难说,但是我相信您不需要特别在新线程中生成进程,而只需让该线程来处理进程即可。 However, if that thread needs to handle intensive computational type of processing as opposed to lots of i/o, then you would want to start a process to handle that. 但是,如果该线程需要处理大量的计算类型的处理,而不是大量的I / O,那么您可能想启动一个处理该类型的过程。

I believe that most of your problem lies in misunderstanding multi-processing vs multithreading. 我相信您的大部分问题都在于对多处理与多线程的误解。

I tried running your code in the following test program and multiprocessing works fine, nothing is blocked: 我尝试在以下测试程序中运行您的代码,并且多处理工作正常,没有任何阻塞:

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()

Run this from your command-line, press the second button(this uses multiprocessing on your function, and I increased the sleep time), and then press the first button. 从命令行运行此命令,按第二个按钮(这在您的功能上使用了multiprocessing功能,并且增加了睡眠时间),然后按第一个按钮。 you should notice that there's output generated when pressing the first button so the program is not blocked. 您应该注意到按下第一个按钮时会生成输出,因此程序不会被阻止。

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

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