Strange threading behaviour

Dave Angel d at davea.name
Thu Jun 21 19:07:02 CEST 2012


On 06/21/2012 11:19 AM, Rotwang wrote:
> Hi all, I'm using Python 2.7.2 on Windows 7 and a module I've written
> is acting strangely. I can reproduce the behaviour in question with
> the following:
>
> --- begin bugtest.py ---
>
> import threading, Tkinter, os, pickle
>
> class savethread(threading.Thread):
>     def __init__(self, value):
>         threading.Thread.__init__(self)
>         self.value = value
>     def run(self):
>         print 'Saving:',
>         with open(os.path.join(os.getcwd(), 'bugfile'), 'wb') as f:
>             pickle.dump(self.value, f)
>         print 'saved'
>
> class myclass(object):
>     def gui(self):
>         root = Tkinter.Tk()
>         root.grid()
>         def save(event):
>             savethread(self).start()
>         root.bind('s', save)
>         root.wait_window()
>
> m = myclass()
> m.gui()
>
> --- end bugtest.py ---
>
>
> Here's the problem: suppose I fire up Python and type
>
> >>> import bugtest
>
> and then click on the Tk window that spawns and press 's'. Then
> 'Saving:' gets printed, and an empty file named 'bugfile' appears in
> my current working directory. But nothing else happens until I close
> the Tk window; as soon as I do so the file is written to and 'saved'
> gets printed. If I subsequently type
>
> >>> bugtest.m.gui()
>
> and then click on the resulting window and press 's', then 'Saving:
> saved' gets printed and the file is written to immediately, exactly as
> I would expect. Similarly if I remove the call to m.gui from the
> module and just call it myself after importing then it all works fine.
> But it seems as if calling the gui within the module itself somehow
> stops savethread(self).run from finishing its job while the gui is
> still alive.
>
> Can anyone help?
>
>

I did not study your code, as I'm not very familiar with tkinter.
However, I think I know your problem:

You do not want to try to start up threads from within a import.  An
import is special, and somehow blocks threading while it's running.

Consequently, a module should not try to do anything too fancy from
within its top-level code.  Add in the traditional:

def main():
    m = myclass()
    m.gui()

if __name__ == "__main__":
    main()

and just run it from the command line, as    python bugtest.py

And if you want to run it from a interactive python session, do the call
to main() after importing it:

>>>> import bugtest
>>>> bugtest.main()


-- 

DaveA



More information about the Python-list mailing list