wx gui multithreadding linux

Plattformunabhängige GUIs mit wxWidgets.
Antworten
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hi

ich hab einen e-m algorithmus den ich in eine wx. gui reingebaut hab und dessen rechnungen ich in einem seperaten thread laufen lassen will... das ganze funktioniert auch wunderbar unter windows allerings unter linux bekomm ich einen fehler und weiss nun nicht mehr weiter... vlt weiss einer von euch dazu einen rat

code:

http://paste.pocoo.org/show/123995/


fehler:
python: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

quant hat geschrieben:das ganze funktioniert auch wunderbar unter windows allerings unter linux bekomm ich einen fehler
Hallo quant!

Ich habe mir deinen Code nicht durchgelesen. Ich habe nur nach "wx.CallAfter" gesucht und nicht gefunden.

Du darfst von einem anderen Thread aus, nicht auf wxPython zugreifen. Du musst die Threads "threadsafe" trennen. Das funktioniert am Besten mit wx.CallAfter. Es gibt noch andere Möglichkeiten -- aber nach diesen habe ich den Code nicht durchsucht.

Falls du glaubst, dass du genug zur Trennung der Threads getan hast, dann melde dich doch bitte hier noch einmal und zeige die Codestelle, in der du die Daten von einem Thread zum anderen Thread übergibst.

Ansonsten: suche hier im Forum nach Threading und wx.CallAfter. Das habe ich hier schon öfter mal beschrieben.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hallo gerold

danke für deine schneller antwort, ich hab mal versucht es mit dem callafter zu machen, bekomme allerdings immernoch den gleichen fehler

ich hab den code im past...

um hilfe wäre ich sehr dankbar

http://paste.pocoo.org/show/124446/
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Linux ist ne schicke Sache. Die meisten Probleme sind aber fehlende Berechtigungen. :-) Selbst die X11 Ressourcen hängen mit Berechtigungen ab. Z.b. wenn Du als Benutzer A eine Applikation auf der grafischen Oberfläche von Benutzer B laufen lassen willst.

Grüße Markus
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

naja das hilft mir hier glaub nicht wirklich weiter, ich hab volle rechte auf meinem rechner .... es liegt glaub wirklich eher daran dass ich irgendwie mit den threads durcheinander komme oder so
BlackJack

Wo kommt denn `ProcessEvent` bei dem Thread her? Ich finde da so beim drüberschauen keine Stelle, wo das definiert wird.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Dein Quelltext ist zu lang als dass ich da jetzt auf die Schnelle den Ueberblick bekommen koennte, aber wie ich sehe, hast du immer noch das Threading-Modul drin. Schmeiss das komplett raus und packe alles in CallAfter-Methoden.

Und befolge das hier:
Gerold hat geschrieben:Ansonsten: suche hier im Forum nach Threading und wx.CallAfter. Das habe ich hier schon öfter mal beschrieben.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

BlackJack hat geschrieben:Wo kommt denn `ProcessEvent` bei dem Thread her?
Ich vermute mal, das soll self.em_obj.ProcessEvent sein, wx.Frame hat sowas naemlich.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

ich versuch mal kurz in worte zu fassen was ich machen will...

also unten in der EM_MoG class hab ich eine iterate funktion, deren berechnungen ich in einem seperaten thread handeln will... diese gibt auch eine rückgabe an die gui...

ich bin noch relativ neu in python, so etwa 3 wochen dabei und ich hab auch schon bischen im forum geschaut und versucht zu verstehen daher kommt dieser process dings... nur leider funktioniert es nicht so wie ich es mir denke

edit:

und jo es ist

Code: Alles auswählen


class ThreadedAction(Thread):
    def __init__(self, em_obj, **kwargs):
        Thread.__init__(self, **kwargs)
        self.em_obj = em_obj

    def run(self):
        print "Performing expensive calculation in %s..."%self.getName()
        
        evt = NewStatusEvent() 
        evt.current_time = time.asctime()
        
       
        while (not self.em_obj._converged and not self.em_obj.stop):

            wx.CallAfter(self.em_obj.ProcessEvent, evt) 
            self.em_obj.iterate()
            
       print 'done.'



BlackJack

@quant: Also ich würde `CallAfter()` ohne eigenes Event verwenden, oder ein eigenes Event, aber dann nicht mit `CallAfter()` sondern mit dem für Events vorgesehenen `PostEvent()`.

Falls die Funktion wirklich so einfach bleibt, könnte man sich auch eine eigene Klasse für den Thread sparen, denn man kann dem Konstruktor auch ein "callable" mitgeben, dass dann im Thread ausgeführt wird.

Ansonsten sollte man immer auch in die wxPython-Demo schauen, an dem Beispielcode kann man eine Menge lernen.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Hier mal ein ganz einfaches Beispiel fuer CallAfter: http://paste.pocoo.org/show/124466/
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu

danke dir :) es läuft jetzt zumindest wieder aber das interface friert auch wieder ein und es stürtzt dann irgendwann ab

das stück code sieht nun so aus

Code: Alles auswählen

#
class ThreadedAction(Thread):
    def __init__(self, em_obj, **kwargs):
        Thread.__init__(self, **kwargs)
        self.em_obj = em_obj

    def run(self):
        print "Performing expensive calculation in %s..."%self.getName()

        
        while (not self.em_obj._converged and not self.em_obj.stop):
            wx.CallAfter(self.em_obj) 
            self.em_obj.iterate()
        print 'done.'
BlackJack

@quant: Du darfst halt aus dem Thread *nichts* an der GUI machen. Ich habe nochmal geschaut was `iterate()` macht: Da greifst Du auf die GUI zu.

Du solltest die Daten und Berechungen strikt(er) von der GUI trennen.

Die `generate_data()` und die `update_*()`-Funktionen machen mir übrigens den Eindruck, als wenn man das zusammen mit den Daten in einer Klasse kapseln könnte.
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu

so ich hab nun mal versucht alle gui sachen aus der iterate raus zu nehmen und es läuft jetzt auch wieder, nur friert mir das interface ein sobald ich das ganze starte... weiss einer vlt wo das problem liegt ?

http://paste.pocoo.org/show/124688/
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu

um mein problem nochma ein wenig zu konkretisieren hab ich das ganze mal nur auf das wesentlich reduziert und gepostet. zur zeit bekomm ich eigendlich nur 2 bilder, einmal das startbild und dann sozusagend die letzte iterationsstufe und dann hängt er sich auf.

was ich gerne hätte wäre ein grafisches update nach jeder iteration und vor allem das menu sollte nicht einfrieren... ich hab deswegen ja versucht die gui vom thread zu trennen...

ich hatte auch schonmal überlegt ob die rechnung vlt viel schneller ist als der gui update und mir desshalb das ganze einfriert und wenn wie könnte man das vlt umgehen ?

für den vollstädnigen code dann bitte den obigen past angucken, wie gesagt hier nur die wichtigen elemente:

Code: Alles auswählen

# hier ist der rechen thread der iterate aufruft und danach die gui updaten soll
class ThreadedAction(Thread):

    def __init__(self, em_obj, **kwargs):

        Thread.__init__(self, **kwargs)

        self.em_obj = em_obj



    def run(self):

        print "Performing expensive calculation in %s..."%self.getName()



        while (not self.em_obj._converged and not self.em_obj.stop):

            self.em_obj.iterate()

            # give function-pointer without brackets

            wx.CallAfter(self.em_obj.updateGUI)

        print 'done.'

# die ganzen initialisierungen ausgelassen... jetzt kommt die klasse
class EM_MoG(wx.Frame):

#wird initialisiert usw.... dann kommt die iterate und dann die update gui

    def iterate(self):





        # store parameters to history-array

        for t in xrange(self._theta_old.count_of_gaussians):

            self._theta_history[self._counter, t] = self._theta_old.mu[t]

            self._theta_history[self._counter, 2+ t] = self._theta_old.sigma[t]

            self._theta_history[self._counter, 4+ t] = self._theta_old.pi[t]



        # get data for y-axis of estimated pdf

        self._y_em = p_x_G_theta(self._pdf_x, self._theta_old)







        # TODO: add legend

        #pl.legend()



        # E-step

        for c in xrange(self._theta_old.count_of_gaussians):

            self._expectation[c, :] = p_c_G_x_theta(c, self._data, self._theta_old)



        # M-step

        theta_new = Theta(2)

        update_mu(self._data, self._expectation, theta_new)

        update_sigma(self._data, self._expectation, theta_new)

        update_pi(self._data, self._expectation, theta_new)



        # compute log-likelihood

        # log-likelihood of initial theta is not logged because it is very low

        # and the curve gets ugly ;-)

        # to try including the initial theta just move this block to first line of the loop

        ll = p_x_G_theta(self._data, theta_new)

        ll = np.log(ll)

        ll = ll.sum()

        self._log_likelihood[self._counter] = ll



        # check convergence

        if self._counter > 0:

            if self._log_likelihood[self._counter] - self._log_likelihood[self._counter-1] < self._epsilon:

                # idea of Gervasio: also check if parameters don't change anymore:

                if np.abs(theta_new.mu - self._theta_old.mu).max() < self._epsilon and np.abs(theta_new.sigma - self._theta_old.sigma).max() < self._epsilon and np.abs(theta_new.pi - self._theta_old.pi).max() < self._epsilon:

                    self._converged = True

            elif self._counter >= self._max_iterations:

                self._converged = True



        # increment counter

        self._counter += 1



        # update theta

        self._theta_old = theta_new



    def updateGUI(self):

        # plot pdf obtained by em-step

        self.b.axes.plot(self._pdf_x, self._y_em)

        self.canvas.draw()





        # plot history of parameters (idea of Omid!!)

        self.d.axes.plot(self._theta_history[:self._counter-1, :])

        self.canvas.draw()



         # plot history of likelihood

        self.c.axes.plot(self._log_likelihood[:self._counter])

        self.canvas.draw()


quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hallo :)

ich hänge irgendwie immernoch an diesem problem, vlt weiss einer was und kann mir vlt auf die sprünge helfen... ich hab aus dem code mal alles rausgenommen was erst mal nicht zu dem problem gehört aber auf wunsch kann ich gerne den kompletten code nochmal linken.

und zwar will ich folgendes machen. ich brauch ein interface mit 4 plots. in einem ist eine random funktion und in den anderen 3 wird der fortschritt der näherung angezeigt. was ich nun will ist: das ich durch start und stop die iterationen anhalten kann bzw. weiterlaufen lassen.

mein problem ist, dass sich das interface immer komplett einfriert wenn ich start drücke...

zu meinem code:

ich hab nur die thread-class drin gelassen um zu zeigen wie ich den update machen will. danach kommt die mainclass in der der canvas erstellt wird etc. allerdings hab ich die iterate funtion etc leer gelassen; ausserdem hab ich die initalisierungen der grafiken etc rausgenommen also es geht mir grad nur um das prinzipielle , also wie ich diesen mechanismus hinbekomme dass er mir nach jedem iterationsschritt die 3 grafen updated und ich weiterin auf das interface zugreifen kann

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf8 -*-

######## imports ###########
#
import matplotlib
matplotlib.use("WXAgg")
matplotlib.interactive(True)
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure
from matplotlib.axes import Subplot
import matplotlib.pyplot as plt
import numpy as np
import pylab as pl
import math
import wx
from threading import Thread
import threading
import time

#
###########################
wx.SetDefaultPyEncoding("iso-8859-15")

class ThreadedAction(Thread):
    def __init__(self, em_obj, **kwargs):
        Thread.__init__(self, **kwargs)
        self.em_obj = em_obj

    def run(self):
        print "Performing expensive calculation in %s..."%self.getName()

        while (not self.em_obj._converged and not self.em_obj.stop):
            self.em_obj.iterate()
            # er soll iterieren und nach jedem iterationsschritt mir die grafiken updaten
            wx.CallAfter(self.em_obj.updateGUI)

####################################################################################
#
class EM_MoG(wx.Frame):
    def __init__(self, task):
        wx.Frame.__init__(self, None, -1, "Interactive Frame v1.0")

        self.fig = Figure((10,10), 75)
        self.canvas = FigureCanvasWxAgg(self, -1, self.fig)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, 1, wx.TOP)
##############################################################################
# hier werden die 4 grafiken initialisiert

        self.a = self.fig.add_subplot(221)
        #self.a.axes.plot(self._pdf_x, self._y_gen)

        # initialisiere die plot-frames
        self.b = self.fig.add_subplot(223)
        self.c = self.fig.add_subplot(222)
        self.d = self.fig.add_subplot(224)

        ################### Controller ######################
        #
        # create start/stop buttons
        self.button_start = wx.Button(self,-1, " Start ", size=(-1,-1))
        self.button_stop = wx.Button(self,-1, " Stop ", size=(-1,-1))
        self.button_exit = wx.Button(self,-1, " Exit ", size=(-1,-1))
        self.cb1 = wx.CheckBox(self, -1, "Show title" )

        # bind actions to the buttons
        self.button_start.Bind(wx.EVT_BUTTON,self.OnStart)
        self.button_stop.Bind(wx.EVT_BUTTON, self.OnStop)
        self.button_exit.Bind(wx.EVT_BUTTON, self.OnExit)

        # pack the buttons in the Sizer
        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
        btnsizer.Add(self.button_start, 1, wx.LEFT)
        btnsizer.Add(self.button_stop, 1, wx.LEFT)
        btnsizer.Add(self.button_exit, 1, wx.RIGHT)

        btnsizer1 = wx.BoxSizer(wx.VERTICAL)
        btnsizer1.Add(self.cb1, 1, wx.DOWN)

        sizer.Add(btnsizer, 0, wx.TOP)
        sizer.Add(btnsizer1, 0, wx.TOP)
        self.SetSizer(sizer)
        self.Fit()
        #
        #####################################################

        # create stop-flag for multithreading
        self.stop = False

    def iterate(self):
# 	hier kommt die iteration welche aus dem thread aufgerufen wird...
        pass    

    def updateGUI(self):
      # hier soll das interface updated werden, wird aufgerufen mit callafter

        # plot pdf obtained by em-step
        #self.canvas.draw()
        #self.b.axes.plot(self._pdf_x, self._y_em)
        #print 'udone.'

        # plot history of parameters (idea of Omid!!)
        #self.d.axes.plot(self._theta_history[:self._counter-1, :])
        #self.canvas.draw()

         # plot history of likelihood
        #self.c.axes.plot(self._log_likelihood[:self._counter])
        #self.canvas.draw()
        #self.canvas.Refresh()
        #self.canvas.Update()
	pass

    def OnStop(self,event=None):
        pass

    def OnStart(self,event=None):
        self.stop = False
        action = ThreadedAction(self)
        action.start()

    def OnExit(self,event=None):
        self.Destroy()

    def iterate_until_converged(self):
        while (not self._converged):
            self.iterate()


if __name__ == '__main__':
    app = wx.PySimpleApp(0)
    frame = EM_MoG('d')
    frame.Show(True)
    app.MainLoop()

Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Schmeiß erstmal die Leerzeilen raus, das kann ja kein Mensch lesen!
EDIT: Im paste sind sie noch drin...
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hmmm was meinst du damit denn genau ?
Antworten