Poodletooth-iLand/panda/python/Lib/site-packages/wx/lib/pubsub/examples/multithreadloop.py
Master Jumblespeed d882959bfa switch to remote
2015-05-18 22:11:33 -04:00

130 lines
4 KiB
Python
Executable file

"""
This test gives an example of how some computation results from an
auxiliary thread could be 'published' via pubsub in a thread-safe
manner, in a 'gui'-like application, ie an application where the
main thread is in an infinite event loop and supports the callback
of user-defined functions when the gui is idle.
The worker thread 'work' is to increment a counter
as fast as interpreter can handle. Every so often (every resultStep counts),
the thread stores the count in a synchronized queue, for later retrieval
by the main thread. In parallel to this, the main thread loops forever (or
until user interrupts via keyboard), doing some hypothetical work
(represented by the sleep(1) call) and calling all registered 'idle'
callbacks. The transfer is done by extracting items from the queue and
publishing them via pubsub.
Oliver Schoenborn
May 2009
:copyright: Copyright 2008-2009 by Oliver Schoenborn, all rights reserved.
:license: BSD, see LICENSE.txt for details.
"""
__author__="schoenb"
__date__ ="$31-May-2009 9:11:41 PM$"
from Queue import Queue
import time
import threading
from pubsub import pub
from pubsub.py2and3 import print_
resultStep = 1000000 # how many counts for thread "result" to be available
def threadObserver(transfers, threadObj, count):
"""Listener that listens for data from testTopic. This function
doesn't know where the data comes from (or in what thread it was
generated... but threadObj is the thread in which this
threadObserver is called and should indicate Main thread)."""
print_(transfers, threadObj, count / resultStep)
pub.subscribe(threadObserver, 'testTopic')
def onIdle():
"""This should be registered with 'gui' to be called when gui is idle
so we get a chance to transfer data from aux thread without blocking
the gui. Ie this function must spend as little time as possible so
'gui' remains reponsive."""
thread.transferData()
class ParaFunction(threading.Thread):
"""
Represent a function running in a parallel thread. The thread
just increments a counter and puts the counter value on a synchronized
queue every resultStep counts. The content of the queue can be published by
calling transferData().
"""
def __init__(self):
threading.Thread.__init__(self)
self.running = False # set to True when thread should stop
self.count = 0 # our workload: keep counting!
self.queue = Queue() # to transfer data to main thread
self.transfer = 0 # count how many transfers occurred
def run(self):
print_('aux thread started')
self.running = True
while self.running:
self.count += 1
if self.count % resultStep == 0:
self.queue.put(self.count)
print_('aux thread done')
def stop(self):
self.running = False
def transferData(self):
"""Send data from aux thread to main thread. The data was put in
self.queue by the aux thread, and this queue is a Queue.Queue which
is a synchronized queue for inter-thread communication.
Note: This method must be called from main thread."""
self.transfer += 1
while not self.queue.empty():
pub.sendMessage('testTopic',
transfers = self.transfer,
threadObj = threading.currentThread(),
count = self.queue.get())
thread = ParaFunction()
def main():
idleFns = [] # list of functions to call when 'gui' idle
idleFns.append( onIdle )
try:
thread.start()
print_('starting event loop')
eventLoop = True
while eventLoop:
time.sleep(1) # pretend that main thread does other stuff
for idleFn in idleFns:
idleFn()
except KeyboardInterrupt:
print_('Main interrupted, stopping aux thread')
thread.stop()
except Exception as exc:
from pubsub import py2and3
exc = py2and3.getexcobj()
print_(exc)
print_('Exception, stopping aux thread')
thread.stop()
main()