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

(yzsuai) #1

program exits. Exits are not necessarily graceful either (you get multiple error messages
in the terminal window).


Because of such constraints, to avoid blocked states, a separately running GUI cannot
generally read data directly if its appearance may be delayed. For instance, in the socket-
based scripts of the prior section (Example 10-25), the after timer loop allows the GUI
to poll for data instead of waiting, and display it as it arrives. Because it doesn’t wait
for the data to show up, its GUI remains active in between outputs.


Of course, the real issue here is that the read/write loop in the guiStreams utility function
used is too simplistic; issuing a read call within a GUI is generally prone to blocking.
There are a variety of ways we might try to avoid this.


Updating GUIs within threads...and other nonsolutions


One candidate fix is to try to run the redirection loop call in a thread—for example, by
changing the launch function in Example 10-28 as follows (this is from file pipe-gui2-
thread.py on the examples distribution):


def launch():
import _thread
_thread.start_new_thread(redirectedGuiShellCmd, ('python -u pipe-nongui.py',))

But then we would be updating the GUI from a spawned thread, which, as we’ve
learned, is a generally bad idea. Parallel updates can wreak havoc in GUIs.


If fact, with this change the GUI fails spectacularly—it hangs immediately on the first
“GO!” button press on my Windows 7 laptop, becomes unresponsive, and must be
forcibly closed. This happens before (or perhaps during) the creation of the new pop-
up scrolled-text window. When this example was run on Windows XP for the prior
edition of this book, it also hung on the first “GO!” press occasionally and always hung
eventually if you pressed the button enough times; the process had to be forcibly killed.
Direct GUI updates in threads are not a viable solution.


Alternatively, we could try to use the Python select.select call (described in Chap-
ter 12) to implement polling for data on the input pipe; unfortunately, select works
only on sockets in Windows today (it also works on pipes and other file descriptors in
Unix).


In other contexts, a separately spawned GUI might also use signals to inform the non-
GUI program when points of interaction arise, and vice versa (the Python signal mod-
ule and os.kill call were introduced in Chapter 5). The downside with this approach
is that it still requires changes to the non-GUI program to handle the signals.


Named pipes (the fifo files introduced in Chapter 5) are sometimes an alternative to
the socket calls of the original Examples 10-23 through 10-25, but sockets work on
standard Windows Python, and fifos do not (os.mkfifo is not available in Windows in
Python 3.1, though it is in Cygwin Python). Even where they do work, we would still
need an after timer loop in the GUI to avoid blocking.


More Ways to Add GUIs to Non-GUI Code | 657
Free download pdf