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

(yzsuai) #1

def producer(self, id):
for i in range(5):
time.sleep(0.1)
self.dataQueue.put('[producer id=%d, count=%d]' % (id, i))


def consumer(self):
try:
data = self.dataQueue.get(block=False)
except queue.Empty:
pass
else:
self.insert('end', 'consumer got => %s\n' % str(data))
self.see('end')
self.after(100, self.consumer) # 10 times per sec


def makethreads(self, event):
for i in range(self.threadsPerClick):
threading.Thread(target=self.producer, args=(i,)).start()


if name == 'main':
root = ThreadGui() # in main thread: make GUI, run timer loop
root.mainloop() # pop-up window, enter tk event loop


Watch for this thread, timer loop, and shared queue technique to resurface later in this
chapter, as well as in Chapter 11’s more realistic PyEdit program example. In PyEdit,
we’ll use it to run external file searches in threads, so they avoid blocking the GUI and
may overlap in time. We’ll also revisit the classic producer/consumer thread queue
model in a more realistic scenario later in this chapter, as a way to avoid blocking a
GUI that must read an input stream—the output of another program.


Thread exits in GUIs


Example 10-19 also uses Python’s threading module instead of _thread. This would
normally mean that, unlike the prior version, the program would not exit if any pro-
ducer threads are still running, unless they are made daemons manually by setting their
daemon flag to True. Remember that under threading, programs exit when only dae-
monic threads remain; the producer threads here inherit a False daemon value from
the thread that creates them, which prevents program exit while they run.


However, in this example the spawned threads finish too quickly to noticeably defer
program exit. Change this script’s time.sleep call to 2.0 seconds to simulate longer-
lived worker threads and witness this effect in action—closing the window after a left-
click erases the window, but the program itself then does not exit for roughly 10 seconds
(e.g., its shell window is paused). If you do the same to the prior _thread version, or
set this version’s threads’ daemon flags to True, the program exits immediately instead.


In more realistic GUIs, you’ll want to analyze exit policies in the context of running
threads, and code accordingly; both nondaemonic threading threads and thread locks
in general can be used to defer exits if needed. Conversely, a perpetually running


GUIs, Threads, and Queues | 639
Free download pdf