[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1

pop atomic?; 4E: runs at most N actions per timer event: looping through all


queued callbacks on each timer event may block GUI indefinitely, but running


only one can take a long time or consume CPU for timer events (e.g., progress);


assumes callback is either short-lived or updates display as it runs: after a


callback run, the code here reschedules and returns to event loop and updates;


because this perpetual loop runs in main thread, does not stop program exit;


#################################################################################


def threadChecker(widget, delayMsecs=100, perEvent=1): # 10x/sec, 1/timer
for i in range(perEvent): # pass to set speed
try:
(callback, args) = threadQueue.get(block=False) # run <= N callbacks
except queue.Empty:
break # anything ready?
else:
callback(*args) # run callback here


widget.after(delayMsecs, # reset timer event
lambda: threadChecker(widget, delayMsecs, perEvent)) # back to event loop


#################################################################################


IN A NEW THREAD - run action, manage thread queue puts for exits and progress;


run action with args now, later run on* calls with context; calls added to


queue here are dispatched in main thread only, to avoid parallel GUI updates;


allows action to be fully ignorant of use in a thread here; avoids running


callbacks in thread directly: may update GUI in thread, since passed func in


shared memory called in thread; progress callback just adds callback to queue


with passed args; don't update in-progress counters here: not finished till


exit actions taken off queue and dispatched in main thread by threadChecker;


#################################################################################


def threaded(action, args, context, onExit, onFail, onProgress):
try:
if not onProgress: # wait for action in this thread
action(args) # assume raises exception if fails
else:
def progress(
any):
threadQueue.put((onProgress, any + context))
action(progress=progress, *args)
except:
threadQueue.put((onFail, (sys.exc_info(), ) + context))
else:
threadQueue.put((onExit, context))


def startThread(action, args, context, onExit, onFail, onProgress=None):
thread.start_new_thread(
threaded, (action, args, context, onExit, onFail, onProgress))


#################################################################################


a thread-safe counter or flag: useful to avoid operation overlap if threads


update other shared state beyond that managed by the thread callback queue


#################################################################################


642 | Chapter 10: GUI Coding Techniques

Free download pdf