<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="">
<frame x='0' y='0' width='792' height='612'>
<para style="head"> </para>
<para style="Bullet"> </para>
<para style="Indent"> </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">Pop Quiz </para>
<para style="Bullet">Slides and scripts 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>
<para style="Bullet">Tips and tricks </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Part 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 1: Thread Intro </para>
<para style="Bullet">What are threads? </para>
<para style="Bullet">GIL </para>
<para style="Bullet">Python threads </para>
<para style="Bullet">Brute force 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="Indent">multiple CPUs, parallelize blocking I/O </para>
<para style="Bullet">Responsiveness </para>
<para style="Indent">e.g. background thread for GUI </para>
<para style="Bullet">Algorithmic simplicity </para>
<para style="Indent">simulations, data passing </para>
<para style="Indent">(mostly skipped in this tutorial) </para>
<para style="Bullet"> </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, OS-level </para>
<para style="Bullet">Thread Library </para>
</frame>
</slide>

<slide title="Python 1.5.2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Python 1.5.2</para>
<para style="Bullet"><font name="Courier">configure --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>
<para style="Bullet">Upgrade to 2.x </para>
<para style="Bullet"> </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="28">  www.python.org/doc/current/api/threads.html</font></para>
<para style="Bullet">Only one Python thread can run </para>
<para style="Indent">Even with multiple CPUs </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>
<para style="Indent">CORBA, XML-RPC, sockets, etc. </para>
<para style="Bullet"> </para>
<para style="Indent"> </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="Use Python Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Use 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
    def run(self):
        self.page = self.getPage()

retriever = Retriever('http://www.foo.com/')
retriever.run()
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="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 Force Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Brute Force Threads </para>
<para style="Bullet">Quick-convert to multiple threads</para>
<para style="Bullet">Need worker class </para>
<para style="Indent">Just inherit from <font name="Courier">threading.Thread</font> </para>
<para style="Bullet">One instance per work unit </para>
<para style="Bullet"> </para>
<para style="Indent"> </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="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="Part 2">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 2 </para>
<para style="Bullet">Thread Theory</para>
<para style="Bullet">Python Thread Library</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">Data protection </para>
<para style="Bullet">Synchronization </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Data Protection">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Data Protection </para>
<para style="Bullet">Keeps shared memory safe </para>
<para style="Bullet">Restricted code access </para>
<para style="Indent">Only one thread accesses block of code</para>
<para style="Bullet">"critical section lock" </para>
<para style="Indent">aka "mutex", "atomic operation"</para>
<para style="Bullet">Similar to DBMS locking </para>
<para style="Bullet"> </para>
<para style="Indent"> </para>
</frame>
</slide>

<slide title="Synchronization">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Synchronization </para>
<para style="Bullet">Synchronize action between threads</para>
<para style="Bullet">Passing data </para>
<para style="Indent">Threads wait for each other to finish tasks</para>
<para style="Bullet">More efficient than polling</para>
<para style="Indent">aka "wait/notify", "rendezvous"  </para>
<para style="Bullet"> </para>
<para style="Indent"> </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="Indent">Handles either protection or synchronization</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="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="Producer/Consumer">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Producer/Consumer </para>
<para style="Bullet">Example: factory </para>
<para style="Indent">One part of the factory <i>produces</i> part of a widget;
another part of the factory <i>consumes</i> widget parts to make complete
widgets.  Trick is to keep it all in balance.</para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="">
<frame x='0' y='0' width='792' height='612'>
<para style="head"> </para>
<para style="Bullet"> </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">Built on top of <font name="Courier">thread</font> </para>
<para style="Indent">Use with both <font name="Courier">threading</font> and <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 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
,,
,out = self.doWork(),...
,queue2.put(output),...
,...,self.in = queue2.get()
,...,out = self.doWork()
,...,queue1.put(output)
,self.in = queue1.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.queue.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="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="Part 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 3: Two Apps </para>
<para style="Bullet">Using Queues </para>
<para style="Indent">spider (thread pool)</para>
<para style="Indent">GUI (Tkinter) (background thread)</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="28">    www.python.org/topics/tkinter/doc.html</font></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="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="FibThreaded Bugs and Exercises">
<frame x='0' y='0' width='792' height='612'>
<para style="head">FibThreaded Bugs and Exercises </para>
<para style="Bullet">Fix deadlock on quit </para>
<para style="Bullet">Fix display of illegal values</para>
<para style="Bullet">Refactor for generic calc object </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Compare Spider/Fib">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Compare Spider/Fib </para>
<para style="Bullet">Shared structures vs. callbacks </para>
<para style="Bullet">New tokens vs. modified tokens </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Recap Part 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Recap Part 3</para>
<para style="Bullet"> </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Part 4">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Part 4: Miscellaneous </para>
<para style="Bullet">Grab bag of useful info </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Data Passing">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Data Passing </para>
<para style="Bullet">Mutables - careful! </para>
<para style="Bullet">References for speedy large objects </para>
<para style="Bullet"> </para>
<para style="Indent"> </para>
</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="Locks vs GIL">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Locks vs GIL </para>
<para style="Bullet">Each lock is unique, a real OS-level lock; GIL is separate </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 reading threads </para>
<spacer height="50"/>
<table widths="(20,368, 368)" style="2code" fieldDelim=";"
heights="(20,5,25,25,25,25)">
;   Threads 1,4;   Threads 2,3,5
;;
;myList.append(work);mutex.acquire()
;...;if myList:
;...;    work = myList.pop()
;...;mutex.release()
</table>
<para style="Bullet"><i>Not</i> safe with UserList </para>
</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="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>
<spacer height="20"/>
<para style="Indent">Also removes <font name="Courier">assert</font> </para>
<para style="Bullet"> </para>
</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="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>
<para style="Bullet">I/O exception: library problems </para>
<para style="Indent">e.g. <font name="Courier">socket.gethostbyname()</font> </para>
</frame>
</slide>

<slide title="Stackless/Microthreads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Stackless/Microthreads </para>
<para style="Bullet"><i>Not</i> OS-level threads </para>
<para style="Bullet">Mix: cooperative and preemptive </para>
<para style="Bullet">Useful for thousands of threads </para>
<para style="Indent">e.g. simulations </para>
<para style="Bullet">More info: </para>
<prefmt style="Code">
    http://www.tismer.com/research/stackless/
    http://world.std.com/~wware/uthread.html
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Killing Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Killing Threads </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Debugging Threads">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Debugging Threads </para>
<para style="Bullet">gdb </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Thread Scheduling">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Thread Scheduling </para>
<para style="Bullet">always on same cpu? </para>
<para style="Bullet">specify CPU? </para>
<para style="Bullet"> </para>
</frame>
</slide>

<slide title="Handling Exceptions">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Handling Exceptions </para>
<para style="Bullet"><font name="Courier">try</font>/<font name="Courier">finally</font> </para>
<para style="Indent">Use to make sure locks get released </para>
<para style="Bullet"><font name="Courier">try</font>/<font name="Courier">except</font> </para>
<para style="Indent">Close down all threads in outer block</para>
<para style="Indent">Be careful to pass <font name="Courier">SystemExit</font> and <font name="Courier">KeyboardInterrupt</font> </para>
<para style="Indent"> </para>
</frame>
</slide>

<slide title="try/finally">
<frame x='0' y='0' width='792' height='612'>
<para style="head">try/finally </para>
<para style="Bullet"> </para>
<para style="Indent"> </para>
</frame>
</slide>

<slide title="try/except">
<frame x='0' y='0' width='792' height='612'>
<para style="head">try/except </para>
<para style="Bullet"> </para>
<para style="Indent"> </para>
</frame>
</slide>

<slide title="Pop Quiz 1">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Pop Quiz 1 </para>
<spacer height="20"/>
<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?
</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>
<spacer height="20"/>
<prefmt style="Normal">
    What are "brute force" threads?

    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>

<slide title="Pop Quiz 3">
<frame x='0' y='0' width='792' height='612'>
<para style="head">Pop Quiz 3 </para>
<spacer height="20"/>
<prefmt style="Normal">
    How do you handle exceptions?
</prefmt>
<para style="Bullet"> </para>
</frame>
</slide>


</section>

</presentation>
