<presentation filename='threads.pdf'>

<stylesheet module="threadstyle" function="threadStyles"/>

<section name='Main'>

<slide title="Title">
<frame x='0' y='0' width='792' height='612'>
<para style="Title">Python Threads</para>
<spacer height="100"/>
<para style="Centered"><font size="50">Aahz</font></para>
<spacer height="20"/>
<para style="Centered"><font name="Courier" size="30">aahz@pobox.com</font></para>
<para style="Centered"><font name="Courier" size="30">http://starship.python.net/crew/aahz/</font></para>
<spacer height="130"/>
<para style="Centered"><font size="40">Powered by PythonPoint</font></para>
<spacer height="20"/>
<para style="Centered"><font name="Courier" size="30">http://www.reportlab.com/</font></para>
</frame>
</slide>

<slide title="Meta Tutorial">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Meta Tutorial </para>
<para style="Bullet">I'm hearing-impaired </para>
<para style="Indent">Please write questions if at all possible</para>
<para style="Bullet">Take notes - or not </para>
<para style="Bullet">Pop Quiz </para>
<para style="Bullet">Slideshow on web </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Contents">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Contents</para>
<para style="Bullet">Goal: Use Threads!</para>
<para style="Bullet">Thread Overview</para>
<para style="Bullet">Python's Thread Library</para>
<para style="Bullet">Two Applications</para>
<para style="Indent">Web Spider</para>
<para style="Indent">GUI Background Thread </para>
</frame>
</slide>

<slide title="Part 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 1 </para>
<para style="Bullet">What are threads? </para>
<para style="Bullet">GIL </para>
<para style="Bullet">Python threads </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Generic Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Generic Threads</para>
<para style="Bullet">Similar to processes </para>
<para style="Bullet">Shared memory </para>
<para style="Bullet">Light-weight </para>
<para style="Bullet">Difficult to set up </para>
<para style="Indent">Especially cross-platform</para>
</frame>
</slide>

<slide title="Why Use Threads?">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Why Use Threads? </para>
<para style="Bullet">Efficiency/speed </para>
<para style="Bullet">Responsiveness </para>
<para style="Bullet">Algorithmic simplicity </para>
</frame>
</slide>

<slide title="Python Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Python Threads</para>
<para style="Bullet">Class-based</para>
<para style="Indent">Use <font name="Courier">threading</font>, not
    <font name="Courier">thread</font>
    </para>
<para style="Bullet">Cross-platform </para>
<para style="Bullet">Thread Library </para>
</frame>
</slide>

<slide title="1.5.2 vs. 2.0">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Python 1.5.2 vs. 2.0 </para>
<para style="Bullet">Compile <font name="Courier">--with-thread</font> </para>
<para style="Indent">Except on MS Windows and some Linux distributions</para>
<para style="Bullet">Multi-CPU bug </para>
<para style="Indent">Creating/destroying large numbers of threads</para>
</frame>
</slide>

<slide title="GIL">
<frame x='0' y='0' width='792' height='612'>
<para style="head">GIL</para>
<para style="Bullet">Global Interpreter Lock (GIL) </para>
<para style="Bullet">Full Documentation: </para>
<para style="Code"><font size="24">  http://www.python.org/doc/current/api/threads.html</font></para>
<para style="Bullet">Only one Python thread can run </para>
<para style="Bullet">GIL is your friend (really!) </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="GIL in action">
<frame x='0' y='0' width='792' height='612'>
<para style="head">GIL in Action </para>
<para style="Bullet">Which is faster?</para>
<spacer height="20"/>
<para style="CodeHeader">One Thread</para>
<prefmt style="Code">
total = 1
for i in range(10000):
    total += 1
total = 1
for i in range(10000):
    total += 1
</prefmt>
<spacer height="45"/>
<table widths="(1,380,380)" style="2code"
heights="(20,5,25,25,25)">
,Two Threads,
,,
,total = 1,total = 1
,for i in range(10000):,for i in range(10000):
,    total += 1,    total += 1
</table>
</frame>
</slide>

<slide title="Dealing with GIL">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Dealing with GIL </para>
<para style="Bullet"><font name="Courier">sys.setcheckinterval()</font> (default 10) </para>
<para style="Bullet">C extensions can release GIL</para>
<para style="Bullet">Blocking I/O releases GIL </para>
<para style="Indent">So does <font name="Courier">time.sleep(<i>!=0</i>)</font></para>
<para style="Bullet">Multiple Processes </para>
</frame>
</slide>

<slide title="Performance Tip">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Performance Tip </para>
<para style="Bullet"><font name="Courier">python -O</font> </para>
<para style="Indent">Also set <font name="Courier">PYTHONOPTIMIZE</font></para>
<para style="Indent">15% performance boost </para>
<para style="Indent">Removes bytecodes (<font name="Courier">SET_LINENO</font>) </para>
<para style="Indent">Fewer context switches!</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="GIL and C Extensions">
<frame x='0' y='0' width='792' height='612'>
<para style="head">GIL and C Extensions </para>
<para style="Bullet">Look for macros: </para>
<para style="Indent"><font name="Courier">Py_BEGIN_ALLOW_THREADS</font></para>
<para style="Indent"><font name="Courier">Py_END_ALLOW_THREADS</font></para>
<para style="Bullet">Some common extensions: </para>
<para style="Indent">mxODBC - yes</para>
<para style="Indent">NumPy - no</para>
</frame>
</slide>

<slide title="Share External Objects 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Share External Objects </para>
<para style="Bullet">Files, GUI, DB connections </para>
</frame>
</slide>

<slide title="Share External Objects 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Share External Objects </para>
<para style="Bullet">Files, GUI, DB connections </para>
<para style="Centered"><font size="160">Don't</font></para>
</frame>
</slide>

<slide title="Share External Objects 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Share External Objects </para>
<para style="Bullet">Files, GUI, DB connections </para>
<para style="Centered"><font size="160">Don't</font></para>
<spacer height="140"/>
<para style="Bullet">Partial exception: <font name="Courier">print</font> </para>
<para style="Bullet">Still need to share? </para>
<para style="Indent">Use worker thread</para>
</frame>
</slide>

<slide title="Create Python Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Create Python Threads </para>
<para style="Bullet">Subclass <font name="Courier">threading.Thread</font> </para>
<para style="Bullet">Override <font name="Courier">__init__()</font> and <font name="Courier">run()</font> </para>
<para style="Bullet">Do <i>not</i> override <font name="Courier">start()</font> </para>
<para style="Bullet">In <font name="Courier">__init__()</font>, call <font name="Courier">Thread.__init__()</font></para>
</frame>
</slide>

<slide title="Using Python Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Using Python Threads </para>
<para style="Bullet">Instantiate thread object </para>
<para style="Indent"><font name="Courier">t = MyThread()</font></para>
<para style="Bullet">Start the thread </para>
<para style="Indent"><font name="Courier">t.start()</font></para>
<para style="Bullet">Methods/attribs from outside thread </para>
<para style="Indent"><font name="Courier">t.put('foo')</font></para>
<para style="Indent"><font name="Courier">if t.done:</font></para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Non-threaded Example">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Non-threaded Example </para>
<spacer height="30"/>
<prefmt style="Code">
class Retriever:
    def __init__(self, URL):
        self.URL = URL
        self.page = self.getPage()

retriever = Retriever('http://www.foo.com/')
URLs = retriever.getLinks()
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Threaded Example">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Threaded Example </para>
<spacer height="30"/>
<prefmt style="Code">
from threading import Thread

class Retriever(Thread):
    def __init__(self, URL):
        Thread.__init__(self)
        self.URL = URL
    def run(self):
        self.page = self.getPage()

retriever = Retriever('http://www.foo.com/')
retriever.start()
while retriever.isAlive():
    time.sleep(1)
URLs = retriever.getLinks()
</prefmt>
</frame>
</slide>

<slide title="Multiple Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Multiple Threads </para>
<spacer height="30"/>
<prefmt style="Code">
seeds = ['http://www.foo.com/',
    'http://www.bar.com/',
    'http://www.baz.com/']
threadList = []
URLs = []

for seed in Seed:
    retriever = Retriever(seed)
    retriever.start()
    threadList.append(retriever)

for retriever in threadList:
    # join() is more efficient than sleep()
    retriever.join()
    URLs += retriever.getLinks()
</prefmt>
</frame>
</slide>

<slide title="import Editorial">
<frame x='0' y='0' width='792' height='612'>
<para style="head"><font name="Courier">import</font> Editorial</para>
<para style="Bullet">How to import </para>
<prefmt style="Code">     from threading import Thread, Semaphore </prefmt>
<para style="Indent">or</para>
<prefmt style="Code">     import threading </prefmt>
<para style="Bullet">Don't use</para>
<prefmt style="Code">     from threading import * </prefmt>
</frame>
</slide>

<slide title="Thread Methods">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Thread Methods </para>
<para style="Bullet">Module functions: </para>
<para style="Indent"><font name="Courier">activeCount()</font> (not useful)</para>
<para style="Indent"><font name="Courier">enumerate()</font> (not useful)</para>
<para style="Bullet">Thread object methods: </para>
<para style="Indent"><font name="Courier">start() </font></para>
<para style="Indent"><font name="Courier">join()</font> (somewhat useful)</para>
<para style="Indent"><font name="Courier">isAlive()</font> (not useful)</para>
<para style="Indent"><font name="Courier">isDaemon() </font></para>
<para style="Indent"><font name="Courier">setDaemon() </font></para>
</frame>
</slide>

<slide title="Unthreaded Spider">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Unthreaded Spider </para>
<para style="Bullet"><font name="Courier">SingleThreadSpider.py</font> </para>
<para style="Bullet">Compare <font name="Courier">Tools/webchecker/</font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Brute Thread Spider">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Brute Thread Spider </para>
<para style="Bullet"><font name="Courier">BruteThreadSpider.py</font> </para>
<para style="Bullet">Few changes from <font name="Courier">SingleThreadSpider.py </font></para>
<para style="Bullet">Spawn one thread per retrieval </para>
<para style="Bullet">Inefficient polling in main loop </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Part 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 2 </para>
<para style="Bullet">Recap </para>
<para style="Bullet">Thread Theory</para>
<para style="Bullet">Python Thread Library</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Recap Part 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Recap Part 1</para>
<para style="Bullet">GIL </para>
<para style="Bullet">Creating threads </para>
<para style="Bullet">Brute force threads </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Thread Order">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Thread Order </para>
<para style="Bullet">Non-determinate </para>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code" fieldDelim="."
heights="(20,5,25,25,25)">
.   Thread 1.   Thread 2
..
.print "a,",.print "1,",
.print "b,",.print "2,",
.print "c,",.print "3,",
</table>
<para style="Bullet">Sample output </para>
<prefmt style="Code">      1, a, b, 2, c, 3,</prefmt>
<prefmt style="Code">      a, b, c, 1, 2, 3,</prefmt>
<prefmt style="Code">      1, 2, 3, a, b, c,</prefmt>
<prefmt style="Code">      a, b, 1, 2, 3, c,</prefmt>
</frame>
</slide>

<slide title="Thread Communication">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Thread Communication </para>
<para style="Bullet">Critical Section Lock </para>
<para style="Indent">Protects shared memory</para>
<para style="Indent">Only one thread accesses chunk of code</para>
<para style="Indent">aka "mutex", or "atomic operation"</para>
<para style="Bullet">Wait/Notify </para>
<para style="Indent">Synchronizes actions between threads</para>
<para style="Indent">Threads wait for each other to finish a task</para>
<para style="Indent">More efficient than polling</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Thread Library">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Thread Library</para>
<para style="Bullet"><font name="Courier">Lock() </font></para>
<para style="Bullet"><font name="Courier">RLock() </font></para>
<para style="Bullet"><font name="Courier">Semaphore() </font></para>
<para style="Bullet"><font name="Courier">Condition() </font></para>
<para style="Bullet"><font name="Courier">Event() </font></para>
<para style="Bullet"><font name="Courier">Queue.Queue() </font></para>
</frame>
</slide>

<slide title="Lock()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Lock() </para>
<para style="Bullet">Basic building block </para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">acquire(<i>blocking</i>)</font> </para>
<para style="Indent"><font name="Courier">release() </font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Critical Section Lock">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Critical Section Lock </para>
<para style="Bullet"> </para>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25,25,25,25,25,25,25,25)">
,   Thread 1,   Thread 2
,,
,mutex.acquire(),...
,if myList:,...
,    work = myList.pop(),...
,mutex.release(),...
,...,mutex.acquire()
,...,if len(myList)&lt;10:
,...,    myList.append(work)
,...,mutex.release()
</table>
</frame>
</slide>

<slide title="GIL and Shared Vars">
<frame x='0' y='0' width='792' height='612'>
<para style="head">GIL and Shared Vars </para>
<para style="Bullet">Safe: one bytecode </para>
<para style="Indent">Single operations against Python basic types (e.g. appending to a list) </para>
<para style="Bullet">Unsafe </para>
<para style="Indent">
Multiple operations against Python variables (e.g. checking 
the length of a list before appending) or any operation that involves 
a callback to a class (e.g. the <font name="Courier">__getattr__</font> hook) 
</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="GIL example">
<frame x='0' y='0' width='792' height='612'>
<para style="head">GIL example </para>
<para style="Bullet">Mutex only one thread </para>
<spacer height="50"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25,25,25,25)">
,   Thread 1,   Thread 2
,,
,myList.append(work),mutex.acquire()
,...,if myList:
,...,    work = myList.pop()
,...,mutex.release()
</table>
</frame>
</slide>

<slide title="dis this">
<frame x='0' y='0' width='792' height='612'>
<para style="head"><font name="Courier">dis</font> this </para>
<para style="Bullet"><font name="Courier">dis</font>assemble source to byte codes </para>
<para style="Bullet">Thread-unsafe statement </para>
<para style="Indent">If a single Python statement uses the same shared variable
across multiple byte codes, or if there are multiple mutually-dependent
shared variables, that statement is not thread-safe
</para>
</frame>
</slide>

<slide title="Misusing Lock()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Misusing Lock()</para>
<para style="Bullet"><font name="Courier">Lock()</font> steps on itself</para>
<spacer height="20"/>
<prefmt style="Code">
mutex = Lock()
mutex.acquire()
  ...
mutex.acquire()   # OOPS!
</prefmt>
</frame>
</slide>

<slide title="Synching threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Synch Two Threads</para>
<spacer height="30"/>
<prefmt style="Code">
class Synchronize:
    def __init__(self):
        self.lock = Lock()
    def wait(self):
        self.lock.acquire()
        self.lock.acquire()
        self.lock.release()
    def notify(self):
        self.lock.release()
</prefmt>
<spacer height="50"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25,25,25,25)">
,   Thread 1,   Thread 2
,,
,self.synch.wait(),...
,...,self.synch.notify()
,...,self.synch.wait()
,self.synch.notify(),...
</table>
</frame>
</slide>

<slide title="RLock()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">RLock() </para>
<para style="Bullet">Mutex only</para>
<para style="Indent">Other threads cannot release RLock()</para>
<para style="Bullet">Recursive </para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">acquire(<i>blocking</i>)</font> </para>
<para style="Indent"><font name="Courier">release() </font> </para>
<para style="Indent"><font name="Courier"> </font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Using RLock()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Using RLock() </para>
<prefmt style="Code">
mutex = RLock()
mutex.acquire()
  ...
mutex.acquire()   # Safe
  ...
mutex.release()
mutex.release()
</prefmt>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25,25,25,25,25,25)">
,   Thread 1,   Thread 2
,,
,mutex.acquire(),...
,self.update(),...
,mutex.release(),...
,...,mutex.acquire()
,...,self.update()
,...,mutex.release()
</table>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Semaphore()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Semaphore() </para>
<para style="Bullet">Restricts number of running threads </para>
<para style="Indent">In Python, primarily useful for simulations (but consider using microthreads)</para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">Semaphore(<i>value</i>) </font> </para>
<para style="Indent"><font name="Courier">acquire(<i>blocking</i>)</font> </para>
<para style="Indent"><font name="Courier">release() </font> </para>
<para style="Indent"><font name="Courier"> </font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Condition()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Condition() </para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">Condition(<i>lock</i>) </font> </para>
<para style="Indent"><font name="Courier">acquire(<i>blocking</i>) </font> </para>
<para style="Indent"><font name="Courier">release() </font> </para>
<para style="Indent"><font name="Courier">wait(<i>timeout</i>) </font> </para>
<para style="Indent"><font name="Courier">notify() </font> </para>
<para style="Indent"><font name="Courier">notifyAll() </font> </para>
<para style="Indent"><font name="Courier"> </font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Using Condition()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Using Condition() </para>
<para style="Bullet">Must use lock </para>
<spacer height="20"/>
<prefmt style="Code">
cond = Condition()
cond.acquire()
cond.wait()        # or notify()/notifyAll()
cond.release()
</prefmt>
<para style="Bullet">Avoid <font name="Courier"><i>timeout</i></font> </para>
<para style="Indent">Creates polling loop, so inefficient</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Event()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Event() </para>
<para style="Bullet">Thin wrapper for <font name="Courier">Condition()</font> </para>
<para style="Indent">Don't have to mess with lock </para>
<para style="Indent">Only uses <font name="Courier">notifyAll()</font>, so can be inefficient</para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">set() </font> </para>
<para style="Indent"><font name="Courier">clear() </font> </para>
<para style="Indent"><font name="Courier">isSet() </font> </para>
<para style="Indent"><font name="Courier">wait(<i>timeout</i>) </font> </para>
<para style="Indent"><font name="Courier"> </font> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="TMTOWTDI">
<frame x='0' y='0' width='792' height='612'>
<para style="head">TMTOWTDI </para>
<para style="Bullet">Perl: </para>
<para style="Indent">There's More Than One Way To Do It </para>
<para style="Bullet">Python: </para>
<para style="Indent">There should be one - and preferably only one - obvious way to do it</para>
<para style="Bullet">Threads more like Perl </para>
</frame>
</slide>

<slide title='Factory 1'>
<frame x='90' y='510' width='300' height='70'>
<para>Body factory</para>
</frame>
<rectangle x='70' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='100' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='130' y='410' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='160' y='390' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='475' y='510' width='300' height='70'>
<para>Wheel factory</para>
</frame>
<rectangle x='480' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='510' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='320' y='240' width='300' height='70'>
<para>Assembly</para>
</frame>
<rectangle x='300' y='180' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='330' y='160' width='150' height='75' fill='(.8,.8,.8)'/>
<customshape module="shapes" class="arrow" initargs="(200,380,280,230,2.5)"/>
<customshape module="shapes" class="arrow" initargs="(600,420,500,230,2.5)"/>
</slide>

<slide title="Factory Objects 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Factory Objects 1 </para>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25,25,25,25)">
,Body,Wheels
,,
,body.list,wheels.list
,body.rlock,wheels.rlock
,body.event,wheels.event
,assembly.event,assembly.event
</table>
<spacer height="10"/>
<para style="CodeHeader">Assembly</para>
<prefmt style="Code">
body.list
body.rlock
body.event
wheels.list
wheels.rlock
wheels.event
assembly.rlock
assembly.event
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Queue()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Queue() </para>
<para style="Bullet">Does not use <font name="Courier">threading</font> </para>
<para style="Indent">Can be used with <font name="Courier">thread</font></para>
<para style="Bullet">Designed for subclassing </para>
<para style="Indent">Can implement stack, priority queue, etc.</para>
<para style="Bullet">Simple! </para>
<para style="Indent">Handles <i>both</i> data protection and synchronization</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Queue() Objects">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Queue() Objects </para>
<para style="Bullet">Methods </para>
<para style="Indent"><font name="Courier">Queue(<i>maxsize</i>) </font> </para>
<para style="Indent"><font name="Courier">put(item,<i>block</i>) </font> </para>
<para style="Indent"><font name="Courier">get(<i>block</i>) </font> </para>
<para style="Indent"><font name="Courier">qsize() </font> </para>
<para style="Indent"><font name="Courier">empty() </font> </para>
<para style="Indent"><font name="Courier">full() </font> </para>
<para style="Bullet">Raises exception when non-blocking </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Using Queue()">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Using Queue() </para>
<spacer height="40"/>
<table widths="(1,380, 368)" style="2code"
heights="(20,5,25,25,25,25,25,25)">
,Thread 1,Thread 2
,,
,output = self.doWork(),...
,queue.put(output),...
,...,self.input = queue.get()
,...,output = self.doWork()
,...,queue.put(output)
,self.input = queue.get(),...
</table>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title='Factory 2'>
<frame x='90' y='510' width='300' height='70'>
<para>Body factory</para>
</frame>
<rectangle x='70' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='100' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='130' y='410' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='160' y='390' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='475' y='510' width='300' height='70'>
<para>Wheel factory</para>
</frame>
<rectangle x='480' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='510' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='320' y='240' width='300' height='70'>
<para>Assembly</para>
</frame>
<rectangle x='300' y='180' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='330' y='160' width='150' height='75' fill='(.8,.8,.8)'/>
<customshape module="shapes" class="arrow" initargs="(200,380,280,230,2.5)"/>
<customshape module="shapes" class="arrow" initargs="(600,420,500,230,2.5)"/>
</slide>

<slide title="Factory Objects 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Factory Objects 2 </para>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25)">
,Body,Wheels
,,
,body.queue,wheels.queue
</table>
<spacer height="10"/>
<para style="CodeHeader">Assembly</para>
<prefmt style="Code">
body.queue
wheels.queue
assembly.rlock
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title='Factory 3'>
<frame x='90' y='510' width='300' height='70'>
<para>Body factory</para>
</frame>
<rectangle x='70' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='100' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='130' y='410' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='160' y='390' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='475' y='510' width='300' height='70'>
<para>Wheel factory</para>
</frame>
<rectangle x='480' y='450' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='510' y='430' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='325' y='310' width='300' height='70'>
<para>Packager</para>
</frame>
<rectangle x='315' y='250' width='150' height='75' fill='(.8,.8,.8)'/>
<frame x='320' y='140' width='300' height='70'>
<para>Assembly</para>
</frame>
<rectangle x='300' y='80' width='150' height='75' fill='(.8,.8,.8)'/>
<rectangle x='330' y='60' width='150' height='75' fill='(.8,.8,.8)'/>
<customshape module="shapes" class="arrow" initargs="(200,380,290,300,2.5)"/>
<customshape module="shapes" class="arrow" initargs="(600,420,490,300,2.5)"/>
<customshape module="shapes" class="arrow" initargs="(390,240,390,210,2.5)"/>
</slide>

<slide title="Factory Objects 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Factory Objects 3 </para>
<spacer height="40"/>
<table widths="(20,368, 368)" style="2code"
heights="(20,5,25)">
,Body,Wheels
,,
,body.queue,wheels.queue
</table>
<spacer height="10"/>
<para style="CodeHeader">Packager</para>
<prefmt style="Code">
while 1:
    body = self.body.queue.get()
    wheels = self.wheels.queue.get()
    self.assembly.put( (body,wheels) )
</prefmt>
<spacer height="10"/>
<para style="CodeHeader">Assembly</para>
<prefmt style="Code">
assembly.queue
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Part 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 3 </para>
<para style="Bullet">Recap </para>
<para style="Bullet">Using Queues </para>
<para style="Indent">spider</para>
<para style="Indent">GUI (Tkinter)</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Recap Part 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Recap Part 2</para>
<para style="Bullet">Data protection and synchronization </para>
<para style="Bullet">Python Thread Library </para>
<para style="Bullet">Queues are good </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Spider w/Queue">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Spider w/Queue</para>
<para style="Bullet"><font name="Courier">ThreadPoolSpider.py</font> </para>
<para style="Bullet">Two queues </para>
<para style="Indent">Pass work to thread pool </para>
<para style="Indent">Get links back from thread pool </para>
<para style="Bullet">Queue for both data and events </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Tkinter Intro">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Tkinter Intro </para>
<spacer height="100"/>
<para style="Centered">This space intentionally left blank </para>
</frame>
</slide>

<slide title="GUI building blocks" outlinelevel='1'>
<frame x='0' y='0' width='792' height='612'>
<para style="head">GUI building blocks </para>
<para style="Bullet">Widgets </para>
<para style="Indent">Windows, buttons, checkboxes, text entry, listboxes </para>
<para style="Bullet">Events </para>
<para style="Indent">Widget activation, keypress, mouse movement, mouse click, timers </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Widgets" outlinelevel='1'>
<frame x='0' y='0' width='792' height='612'>
<para style="head">Widgets </para>
<para style="Bullet">Geometry manager </para>
<para style="Bullet">Register callbacks </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Events" outlinelevel='1'>
<frame x='0' y='0' width='792' height='612'>
<para style="head">Events </para>
<para style="Bullet">Event loop </para>
<para style="Bullet">Trigger callbacks </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Tkinter resources" outlinelevel='1'>
<frame x='0' y='0' width='792' height='612'>
<para style="head">Tkinter resources </para>
<para style="Bullet">Web </para>
<para style="Code"><font size="26">    http://www.python.org/topics/tkinter/doc.html</para>
<para style="Indent"> </para>
<para style="Bullet">Books </para>
<para style="Indent"><i>Python and Tkinter Programming</i>, John E. Grayson </para>
<para style="Indent"> </para>
<para style="Bullet"> </para>
<para style="Indent"> </para>
</frame>
</slide>

<slide title="Fibonacci">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Fibonacci </para>
<para style="Bullet"><font name="Courier">Fibonacci.py</font> </para>
<para style="Bullet">UI freezes during calc </para>
<para style="Bullet">Frequent screen updates slow calc </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Threaded Fibonacci">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Threaded Fibonacci </para>
<para style="Bullet"><font name="Courier">FibThreaded.py</font> </para>
<para style="Bullet">Tkinter needs to poll </para>
<para style="Indent">Use <font name="Courier">after</font> event</para>
<para style="Bullet">Single-element queue </para>
<para style="Indent">Use in non-blocking mode to minimize updates</para>
<para style="Bullet">Must use "Quit" button </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Pop Quiz 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Pop Quiz 1 </para>
<prefmt style="Normal">
How are threads and processes similar and different?

What is the GIL?

In what ways does the GIL make thread programming easier 
and harder?

How do you create a thread in Python?

What should not be shared between threads?

What are "brute force" threads?
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Pop Quiz 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Pop Quiz 2 </para>
<prefmt style="Normal">
Explain what each of the following is used for:
    Lock()
    RLock()
    Semaphore()
    Condition()
    Event()
    Queue.Queue()

Why are queues great?
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

</section>

</presentation>
