【问题标题】:Wxpython multi-threading is running threads sequentially not all at onceWxpython 多线程是按顺序运行线程,而不是一次全部运行
【发布时间】:2015-02-27 01:00:49
【问题描述】:
import wx
import os
import sys
import wx.lib.plot as plot
import datetime
import urllib
import threading

pathstr = '/media/meant2b/My Passport/C Drive/Convert/GFSMaps/'

class Frame(wx.Frame):
    def __init__(self, parent, id, title):
        style = wx.DEFAULT_FRAME_STYLE ^ (wx.RESIZE_BORDER)
        wx.Frame.__init__(self, parent, id, title=title, size = (1024, 768), style=style)
        self.Center()
        self.panel = wx.Panel(self)
        self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.panel.SetFocus()
        self.panel.SetBackgroundColour('White')
        self.bitmap = None
        self.PhotoMaxSize_1 = (881)        
        self.CreateMenuBar()
        self.model = 0
        self.map = 0
        self.dMinus = 0
        self.Model = ['00', '06', '12', '18']
        self.MDay = ['000','003','006','009','012','015','018','021','024','027','030','033','036','039','042','045','048','051','054','057','060','063','066','069','072','075','078','081','084','087','090','093','096','099','102','105','108','111','114','117','120','123','126','129','132','135','138','141','144','147','150','153','156','159','162','165','168','171','174','177','180','183','186','189','192','204','216','228','240','252','264','276','288','300','312','324','336','348','360','372','384']
        self.MapType = 0


    def gif1(self, event):
        pathstr = '/'
        for self.dMinus in range(4, -1, -1):
            self.MoveCalendar() #sets date
            for Counter1 in range(0, 4):
                for Counter2 in range(0, 81):
                    if os.path.isfile(pathstr + self.strDate + self.Model[Counter1] + self.MDay[Counter2] + '.gif') == True:
                    continue
                    url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/' + self.strDate + '/' + self.Model[Counter1] + '/gfs_namer_' + self.MDay[Counter2] + '_1000_500_thick.gif'
                    urllib.urlretrieve(url,str(pathstr + self.strDate + self.Model[Counter1] + self.MDay[Counter2] + '.gif'))
                    statinfo = os.stat(str(pathstr + self.strDate + self.Model[Counter1] + self.MDay[Counter2] + '.gif'))
                    if statinfo.st_size<21000L:
                        os.remove(str(pathstr + self.strDate + self.Model[Counter1] + self.MDay[Counter2] + '.gif'))
                        counter2 = 80

         for Counter1 in range (3, -1, -1):
             url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/' + self.Model[Counter1] + '/gfs_namer_384_850_temp_mslp_precip.gif'
             urllib.urlretrieve(url,pathstr + '850Temp384.gif')
             statinfo = os.stat(pathstr + '850Temp384.gif')
             if statinfo.st_size<21000:
                 os.remove(pathstr + '850Temp384.gif')
                 continue
             else:
                for Counter2 in range(0, 81):
                    url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/' + self.Model[Counter1] + '/gfs_namer_' + self.MDay[Counter2] + '_850_temp_mslp_precip.gif'
                    urllib.urlretrieve(url,pathstr + '850Temp' + self.MDay[Counter2] + '.gif')
                    statinfo = os.stat(pathstr + '850Temp' + self.MDay[Counter2] + '.gif')
                    if statinfo.st_size<21000:
                        os.remove(pathstr + '850Temp' + self.MDay[Counter2] + '.gif')
        print('SHOW ME')
        self.VGFS(event)

    def gif2(self, event):
        url = 'http://www.cpc.ncep.noaa.gov/products/precip/CWlink/daily_ao_index/ao.sprd2.gif'
        urllib.urlretrieve(url,pathstr + '/AO.gif')

        url = 'http://www.cpc.ncep.noaa.gov/products/precip/CWlink/pna/nao.sprd2.gif'
        urllib.urlretrieve(url,pathstr + '/NAO.gif')

        url = 'http://www.cpc.ncep.noaa.gov/products/precip/CWlink/pna/pna.sprd2.gif'
        urllib.urlretrieve(url,pathstr + '/PNA.gif')

        url = 'http://www.esrl.noaa.gov/psd/enso/mei/ts.gif'
        urllib.urlretrieve(url,pathstr + '/MEI.gif')
     '''
     And numerous more gifs/pngs as well
     '''

    def All(self, event):
        dl0 = threading.Thread(target = self.GFS(event))
        print('MESHOW')
        dl0.start()

        dl1 = threading.Thread(target = self.Oscillators(event))
        print('MEGO')
        dl1.start()

class App(wx.App):

    def OnInit(self):
        self.frame = Frame(parent = None, id =-1)
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__=='__main__':
    app = App()
    app.MainLoop()

我正在跳过大量代码。当我在 wxpython 中运行上述代码时,它运行良好,除了它按顺序运行代码,而不是同时运行所有代码。每个线程都在下载大量的 gif 和 png 文件...足够我想拆分操作以节省一些时间。它正在调用每个“线程”,但它正在等待 dl0 在运行 dl1 之前完成。我可以通过查看存储文件的目录来判断。我该如何改变它以获取它,以便它同时调用两个线程?

我将添加它,但我不知道这在 wxpython 与 tkinter 中的线程中是否会有所不同。在 tkinter 中,为了让它工作,我从来不需要添加 Thread.<strong>init</strong>(self)(由于某种原因这不会让我做 __),就像我在 wxpython 编码中看到的那样。

我现在只是想将两个单独运行的正确程序合并为一个。我也在从 tkinter 更改为 wxpython。

【问题讨论】:

  • 我们必须看看 gifs1 和 gifs2 做了什么来诊断。
  • 我添加了额外的代码,希望能显示问题。

标签: wxpython


【解决方案1】:

排队

dl0 = threading.Thread(target = self.GFS(event))

您将计算结果self.GFS(event) 分配给target。虽然理论上这个结果可能是一个可调用的对象,但不太可能,我猜你真正的意思是

dl0 = threading.Thread(target=self.GFS, args=[event])

当然,dl1 也是如此。

关于线程的一些补充说明

假设我有一些带有一些副作用的简单函数和返回值None,像这样:

>>> import threading
>>> def foo():
        print "I am FOO!"

现在我可以在单独的线程中启动此函数,如下所示:

>>> t = threading.Thread(target=foo)
>>> t.start()
I am FOO!

只要我用它的start 方法启动线程t,它就会查看target 是否已定义并可调用,既然是这样,它就会调用它,然后foo 打印它的文本。

如果我错误地将foo 本身而不是foo() 分配给参数target,会发生什么情况?让我们看看:

>>> t = threading.Thread(target=foo())
I am FOO!
>>> t.start()

在我执行赋值的那一刻,Python 必须计算foo() 的值,恰好是None(因为foo 没有返回值),在这个计算过程中,@ 的副作用987654341@被触发。

但是当我用start() 启动线程t 时,target 的值是None,这是不可调用的,所以什么也没有发生。

在你的情况下,我怀疑无论self.GFS(event) 做什么魔法,它都是在分配期间在主线程中完成的,而dl0.start() 绝对什么都不做。这就解释了为什么 GFSOscillators 的魔力似乎是按顺序发生的:它们都发生在主线程中,而两个辅助线程则什么都不做。

关于 wx 的一些补充说明

当然可以混合wxthreading,但是混合有一些粗糙的边缘。例如,出于单元测试的目的,可能需要在单独的线程中创建和销毁多个 wx.App 对象,但是 wxWidgets(以及因此 wxPython)强烈构建在假设只有一个 wx.App-Object 的基础上,并且它驻留在主线程中。

我更喜欢将繁重的计算(当然应该有自己的线程)和所有 wx-Gui-stuff 尽可能分开。您可能需要考虑如下模式:

首先,GUI端:

# ...

import wx.lib.newevent

ComputationDoneEvent, EVT_COMPUTATION_DONE = wx.lib.newevent.NewEvent()

# ...

class MainFrame(wx.Frame):

    def __init__(self):
        # ...
        self.Bind(EVT_COMPUTATION_DONE, self.OnComputationDone)

    def OnMainButtonPressed(self, evt):
        # The user pressed the big fat button and wants
        # some heavy computation performed
        t = threading.Thread(target=heavy_computation,
                             args=[self, arg1, arg2],
                             daemon=True)
        t.start()
        self.statusbar.SetStatusText("Busy doing stuff...")
        # eventually disable input, change cursor to busy,
        # whatever is appropriate in your case, and how
        # much it makes sense for the user to proceed
        # with other stuff while waiting for the result.

    def OnComputationDone(self, evt):
        # this gets called later when the computation is done
        self.statusbat.SetStatusText("Result: " + str(evt.result))
        # enable input, change cursor, whatever

现在,繁重的计算方面:

def heavy_computation(mother, arg1, arg2):
    # First, all the stuff that has nothing to do with
    # the GUI
    perform_some_side_effects()
    result = some_more_computations(arg1, arg2)

    # Now we have to inform the wx side that we are done
    evt = ComputationDoneEvent(result=result)
    wx.PostEvent(mother, evt)

当然,对于非常复杂和乏味的东西,您会想要提供某种进度表,也许您想要在 GUI 的某处显示heavy_computation 中引发的异常。但我希望你能明白。有关更完整的示例,另请参阅 http://wxpython.org/Phoenix/docs/html/lib.newevent.html

【讨论】:

    【解决方案2】:

    如果不查看更多代码,我真的无法说出为什么它不起作用。上个月我确实创建了一个 wxPython 下载应用程序,不过您可以查看一下以获取灵感:

    基本上我只是从 threading 模块继承 Thread,让它使用 requests 下载文件,然后更新 wxPython GUI。要开始下载,我使用 url 和其他几个参数调用我的下载线程。我可以多次这样做没有问题。

    我的一位读者举了这个例子,并在此处对其进行了一些扩展:

    希望对您有所帮助。

    【讨论】:

    • 我开始徘徊...我一直在阅读和看到相同的东西...运行一个线程,而不是多个线程。我正在尝试同时运行多个线程。现在,除了下载图像之外,我并没有尝试对程序做任何事情,而我出去做其他事情,这无论如何都是程序的意图。我希望能够在我不在网上冲浪/在完整的单独程序中做其他事情时运行多个线程。程序完成后,我将查看下载的内容。我还没有看到有人使用多线程。
    • 我在 url 之后添加了 url 以一次下载多个文件,它似乎有效。但是如果你想要真正的并行下载,那么你可能想要使用多处理。
    猜你喜欢
    • 2018-10-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多