A thread import problem

Bruce Sherwood bruce.sherwood at gmail.com
Sat Jul 21 19:10:05 EDT 2012


On Sat, Jul 21, 2012 at 4:16 PM, Dennis Lee Bieber
<wlfraed at ix.netcom.com> wrote:
> On Sat, 21 Jul 2012 10:11:30 -0600, Bruce Sherwood
> <bruce.sherwood at gmail.com> declaimed the following in
> gmane.comp.python.general:
>
>
>>
>> ---------------------------
>> testABA.py -- execute this file
>>
>> from ABA import *
>> print('exec testABA')
>> from math import sin
>> print(sin(3.14159/6))
>>
>> ----------------------------
>> testABA_noimport.py -- a version of testABA.py without the import of ABA
>>
>> print('exec testABA_noimport')
>> from math import sin
>> print(sin(3.14159/6))
>>
>> -----------------------------
>> ABA.py
>>
>> from thread import start_new_thread
>> from time import sleep
>> import sys
>>
>> user = 'testABA_noimport'
>> start_new_thread(lambda: __import__(user), ())
>> print('after start_new_thread\n')
>>
>> while True:
>>     sleep(1)
>>
>
>         And all along you are still coding where imported modules are doing
> work DURING THE IMPORT. Anything beyond initializing module level
> constants or importing modules needed by the module should be placed
> into a function which can be executed by the top-level importer AFTER
> the import has finished.
>
> -=-=-=-=- testABA.py
> print ("testABA: top")
>
> from math import sin, pi
> import time
>
> print ("testABA: defining worker function")
> def runner():   #this is the key -- a function IN the module
>                 #that does the real work
>     print ("testABA.runner: starting work\n")
>     time.sleep(2.5)
>     print (sin(pi))
>     time.sleep(2.5)
>     print ("\ntestABA.runner: end of work")
>
> print ("testABA: after set-up")
>
> if __name__ == "__main__":
>     print ("testABA: was not an import, running main task")
>     runner()    #invoke the function if module is not imported
>     print ("testABA: end")
> -=-=-=-=-
>
> -=-=-=-=- ABA.py
> import threading
>
> USER = "testABA"
>
> print ("ABA: importing " + USER)
> modl = __import__(USER)
>
> print ("ABA: starting runner")
> th = threading.Thread(target=modl.runner)
> th.start()
>
> print ("ABA: waiting for completion")
> th.join()
>
> print ("ABA: done")
> -=-=-=-=-
>
>         And showing the results...
>
> -=-=-=-=-
> E:\UserData\Wulfraed\My Documents\Python Progs>testABA
> testABA: top
> testABA: defining worker function
> testABA: after set-up
> testABA: was not an import, running main task
> testABA.runner: starting work
>
> 1.22460635382e-016
>
> testABA.runner: end of work
> testABA: end
>
> E:\UserData\Wulfraed\My Documents\Python Progs>ABA
> ABA: importing testABA
> testABA: top
> testABA: defining worker function
> testABA: after set-up
> ABA: starting runner
> testABA.runner: starting work
>
> ABA: waiting for completion
> 1.22460635382e-016
>
> testABA.runner: end of work
> ABA: done
> -=-=-=-=-
>
>         Note that "testABA.py" is designed to be used as a stand-alone
> program, but is also designed to be imported where all the real work is
> done from a function that is NOT run during the import. The program that
> imports "testABA" is then responsible for actually starting the worker.
>
>         I put the sleeps into testABA.runner() so that you can see that the
> main process isn't blocked (note the "ABA: waiting..." output)
>
>
> --
>         Wulfraed                 Dennis Lee Bieber         AF6VN
>         wlfraed at ix.netcom.com    HTTP://wlfraed.home.netcom.com/
>
> --
> http://mail.python.org/mailman/listinfo/python-list

Thanks, but the problem I need to solve does not permit putting a
function like runner in the main program. I'm constrained to being
able to handle the API of VPython (vpython.org), which lets you write
programs like the following (call it user.py), which animates a 3D
cube moving to the right, using OpenGL:

from visual import box
b = box()
while True:
    b.pos.x += 0.001

In VPython at present, the visual module sets up (using C++ and Boost)
a secondary thread that periodically updates the 3D scene using the
current objects and their attributes, and handles events. On the Mac
this is done with Carbon, which is dying, so I need to base VPython on
the Mac on Cocoa, for which the interact loop must be in the primary
thread. Hence my need to turn the architecture inside out while
nevertheless handling the existing API.

The cleanest scheme is to have the user's program user.py import a
module "visual" that spawns a new process, "python visual2.py
user.py", where visual2.py reads the source from user.py, comments out
the "import visual", and exec's this modified source in a secondary
thread. This works because visual2.py is now the main module.
Unfortunately, if user.py is run from IDLE, print output goes to a
terminal window rather than to the IDLE shell window, and I don't know
how to direct the output to that shell window.

For this reason I've been experimenting with other schemes, and it
took a while to understand that a thread spawned in an imported module
cannot do imports. I've even managed to carry out a real kludge of
executing imports found in user.py at the top level of visual,
creating a dictionary of globals to pass to an exec of the source in
user.py with all imports there commented out. It works, but ugh.

Bruce Sherwood



More information about the Python-list mailing list