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

(yzsuai) #1

threading thread might preclude a desired shutdown if nondaemonic. See Chapter 5
for more on program exits and daemonic threads (and other scary topics!).


Placing Callbacks on Queues


In the prior section’s examples, the data placed on the queue is always a string. That’s
sufficient for simple applications where there is just one type of producer. If you may
have many different kinds of threads producing many different types of results running
at once, though, this can become difficult to manage. You’ll probably have to insert
and parse out some sort of type or action information in the string so that the GUI
knows how to process it.


Imagine an email client, for instance, where multiple sends and receives may overlap
in time; if all threads share the same single queue, the information they place on it must
somehow designate the sort of event it represents—a downloaded mail to display, a
progress indicator update, a successful send completion, and so on. This isn’t entirely
hypothetical: we’ll confront this exact issue in Chapter 14’s PyMailGUI.


Luckily, queues support much more than just strings—any type of Python object can
be placed on a queue. Perhaps the most general of these is a callable object: by placing
a function or other callable object on the queue, a producer thread can tell the GUI
how to handle the message in a very direct way. The GUI simply calls the objects it
pulls off the queue. Since threads all run within the same process and memory space,
any type of callable object works on a queue—simple functions, lambdas, and even
bound methods that combine a function with an implied subject object that gives access
to state information and methods. Any updates performed by the callback object up-
date state shared across the entire process.


Because Python makes it easy to handle functions and their argument lists in generic
fashion, this turns out to be easier than it might sound. Example 10-20, for instance,
shows one way to throw callbacks on a queue that we’ll be using in Chapter 14 for
PyMailGUI. This module comes with a handful of tools. Its ThreadCounter class can be
used as a shared counter and Boolean flag (for example, to manage operation overlap).
The real meat here, though, is the queue interface functions—in short, they allow cli-
ents to launch threads which queue their exit actions, to be dispatched in the main
thread by a timer loop.


In some ways this example is just a variation on those of the prior section—we still run
a timer loop here to pull items off the queue in the main thread. For both responsiveness
and efficiency, this timer loop pulls at most N items on each timer event, not just one
(which may take too long or incur overheads for a short timer delay), and not all queued
(which may block indefinitely when many items are produced quickly). We’ll leverage
this per-event batching feature to work through many progress updates in PyMailGUI
without having to devote CPU resources to quick timer events that are normally
unnecessary.


640 | Chapter 10: GUI Coding Techniques

Free download pdf