cse 399-004: python programmingcse39904/lectures/06-withthreads.pdf•python's with-statement...

56
CSE 399-004: Python Programming Lecture 06: with-statements and threads February 19, 2007 http://www.seas.upenn.edu/~cse39904/

Upload: others

Post on 08-Jul-2020

11 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

CSE 399-004:Python Programming

Lecture 06: with-statements and threadsFebruary 19, 2007

http://www.seas.upenn.edu/~cse39904/

Page 2: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Announcements

• Projects• Feedback on proposals by next week• No need to start on these right now• Due date: Friday April 20, 2007 at 5pm

• Homework 6• Already posted• Due one week from today

2

Page 3: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The "with" statement(Tutorial, Section 8.7)

Page 4: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Working with files

4

file = open("foo.txt")data = file.read()print datafile.close()

Page 5: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Working with files

4

file = open("foo.txt")data = file.read()print datafile.close()

It's important to close a file when you're done with it.

Page 6: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Working with files

4

file = open("foo.txt")data = file.read()print datafile.close()

Suppose now that all sorts of things can go wrong here. How many places are you going to have to call file.close() now?

Page 7: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

The with-statement

5

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data

Page 8: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

The with-statement

5

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data

Signals to the interpreter that this module uses with-statements, which aren't standard yet. Must be the first non-doc string code in the file.

Page 9: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The with-statement

6

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data

the object managed by this with-statement

Page 10: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The with-statement

6

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data we can use file to

refer to the file object

Page 11: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The with-statement

7

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data

No matter how we exit this block, file.close() will be always be called.

Page 12: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The with-statement

7

• Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called

• What a with-statement does for a given object depends on the exact object at hand

from __future__ import with_statement

with open("foo.txt") as file: data = file.read() print data

Page 13: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Adding support for with-statements

• See Section 3.4.9 of the Language Reference for information on the __enter__ and __exit__ methods

• These two methods define how with-statements work:• __enter__ defines the initialization behavior• __exit__ defines the clean-up behavior

• You don't have to understand these two methods if you only want to use with-statements

8

Page 14: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Threads: Overview

Page 15: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Operating systems and processes

• Definition: A process is a running program

• An OS manages the running of multiple processes on limited hardware resources

• One process cannot directly access the memory of another process

• Processes are forced to share CPU time

• But each process thinks it has its own CPU and vast amounts of memory (~4GB on a 32-bit machine)

10

Page 16: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Doing multiple things at once

• Often, a process wants to do multiple things at once

• Typical example: Web browser• One window might be loading a page• Another window might need to animate a movie• The user might be typing into a form

• It doesn't make sense for each of these tasks to be its own process — they need share state

11

Page 17: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Threads

• Threads allow a process to do multiple things at once

• A process can have multiple threads• Each thread has its own local state• All threads share the same global state

• Aside from the sharing of global state, a thread is conceptually the same as a process

• However, how threads are scheduled to be run is dependent on how they're implemented

12

Page 18: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Threads in Python

• Support for multi-threaded programs in Python is provided by the thread and threading modules

• Python threads are pre-emptive in that threads may be interrupted at arbitrary times

• But, due to how the Python interpreter is implemented, only one thread can be running at any given time

• So why use multiple threads in Python?• Input/output latency• Conceptually cleaner code

13

Page 19: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Caveats about Python threads

• Not all operations are thread-safe

• Some operations may not behave correctly when multiple threads are running

• Some operations may block the entire process, meaning that no thread gets to run until the operation completes

• It's difficult to program for pre-emptive threads• You never know when you might be interrupted• What happens if you're modifying global state?

14

Page 20: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Common problems

• Race conditions: Code may be sensitive to who gets to do something first

• Deadlock: Two threads might both get stuck waiting for the other thread to do something

• Starvation: One thread may never get to run• This can happen even with pre-emptive threads

• Simply engineer your code in just the right way…

15

Page 21: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Goal for today's class

• Introduce you to (some of ) Python's support for threads

• Non-goal: Make you an expert on multi-threaded programming and all its issues

• Multi-threaded programming is difficult and better discussed in a class on concurrent systems, for example

16

Page 22: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The threading module

Page 23: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The Thread class

• If you want to create your own threads, you should create a subclass of the Thread class

• Subclasses should:• Always call Thread.__init__()

• Python will complain if you don't do this• The Thread class does some required initialization

• Override the run() method• This method defines what the thread does• By default, it does nothing

• To start a thread object executing, invoke start()

18

Page 24: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Thread: Example

19

sum = 0

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sum += j

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()print sum

Page 25: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Thread: Example

19

sum = 0

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sum += j

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()print sum

Needed to ensure that the sum refers to the global version of sum. That is, sum is shared between all threads.

Page 26: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Possible outputs from that program

20

• Run the program multiple times, and you may see:• 311738101• 6800400028• 9999900000 ("correct")• 5317180266• 7030865778• 6795902278• 16380465• 5001560115• 106975597

• What is going on here??

Page 27: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Problem 1: Printing sum too early

• The "main" thread prints out sum before the other two threads have finished executing

• To see this, tweak the definition of the class

21

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sum += j print "Done".

Page 28: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

New sample output

• Run the program a couple of times

• 3352925422Done.Done.

• 104111214Done.Done.

• The "main" thread (the one started by Python when it first starts executing your code) is indeed printing sum far too early

22

Page 29: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Thread.join()

• The join() method, when called on a thread object T, causes the calling thread to block until T finishes

23

sum = 0

class SumThread(threading.Thread): ...

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()th1.join()th2.join()print sum

Page 30: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

New sample output

• Run this new version a couple of times

• Done.Done.9516678490

• Done.Done.9999900000

• Um… something is still not quite right…

24

"correct"

Page 31: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Problem 2: Lack of atomicity

• The line sum += j does not execute atomically• Thread has to read sum• Then compute sum + j• Then set sum to what it just computed

• The thread could be interrupted between any of those actions, and sum could be changed without it knowing

• Atomic operations, on the other hand, compute as if they were never interrupted by other threads

25

Page 32: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Mutual exclusion

• In order to effectively use shared state, we need a way to prevent threads from stepping all over each other

• Mutual exclusion refers to making sure that only some number of threads, often just 1, are doing something

• Some Python constructs which provide mutual exclusion:• Lock and RLock• Semaphore and BoundedSemaphore• Condition (won't discuss this today)

26

Page 33: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Lock

• A Lock supports two atomic operations• acquire()• release()

• Initially, a lock is in the untaken state• acquire() causes it to be taken• release() causes it to be untaken

• You can't:• release an untaken lock — this is an error• acquire a taken lock — call blocks until lock is released

• Basic idea: "take a lock" if you need exclusive access27

Page 34: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

RLock

• A variation on Lock — the "R" stands for "reentrant"

• If a thread has already called acquire() on an RLock and attempts to acquire() it again, the second call succeeds

• With a plain Lock, the second call would block, thus leading to a thread deadlocked with itself

• Aside: Java's implicit locks used in implementing synchronized are reentrant

28

Page 35: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

sum = 0sumLock = threading.Lock()

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sumLock.acquire() sum += j sumLock.release()

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()th1.join()th2.join()print sum 29

Page 36: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

sum = 0sumLock = threading.Lock()

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sumLock.acquire() sum += j sumLock.release()

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()th1.join()th2.join()print sum 29

This is a function which returns an object. (The capitalization is misleading.)

Page 37: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

sum = 0sumLock = threading.Lock()

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): sumLock.acquire() sum += j sumLock.release()

th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()th1.join()th2.join()print sum 29

Before we do anything with sum, acquire the corresponding lock. When we're done, release it.

Page 38: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

New sample output

• Run this new version a couple of times

• You will always get: 9999900000

• Wasn't that fun…

30

Page 39: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Semaphore

• A semaphore is, conceptually, a non-negative integer which can be incremented/decremented atomically

• Semaphore(n) creates a semaphore with initial value n

• release() increments the semaphore's value

• acquire() decrements the semaphore's value

31

Page 40: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Semaphore (continued)

• If the value is zero when acquire() called, then the call blocks, i.e., the calling thread waits until the value becomes non-zero

• If multiple threads are blocked on a semaphore when release() is called, one of them is chosen randomly and allowed to proceed

• Use semaphores when you need to limit the number of threads than can simultaneously be doing something

32

Page 41: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

BoundedSemaphore

• BoundedSemaphore(n) creates a semaphore with initial value n, and it's value can never exceed n

• BoundedSemaphore(1) is equivalent to a simple lock

• Probably more useful than Semaphore: extra calls to release() usually correspond to serious bugs

33

Page 42: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

with statements

• Both semaphores and locks can be used withwith-statements in a fairly natural way

• The with-statement automatically calls acquire() before executing the block and release() upon exit the block

34

with some_lock: # do stuff

with some_semaphore: # do more stuff

Page 43: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

sum = 0sumLock = threading.Lock()

class SumThread(threading.Thread): def __init__(self, i): threading.Thread.__init__(self) self.i = i def run(self): global sum for j in range(0, self.i): with sumLock: sum += j th1 = SumThread(100000)th2 = SumThread(100000)th1.start()th2.start()th1.join()th2.join()print sum 35

This code does the exact same thing as the previous version.

Page 44: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Daemon threads

• Python keeps running as long as some thread is running

• You can call setDaemon(True) on a Thread object to turn it into a "daemon" thread

• False turns it to a normal thread• Daemon status is inherited from the creating thread

• If only daemon threads are running, Python will exit

• You must call setDaemon() before calling start()

36

Page 45: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

A final note: Documentation

• thread module: Section 15.2 in the Library Reference• threading module: Section 15.3 in the Library Reference

• Not everything in threading was presented here

• The thread module was also not presented here• It's low level, but also simpler• The threading module provides a nicer interface

37

Page 46: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Homework 6

Page 47: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The dining philosophers

• Some philosophers are sitting at a table

• Between each pair of philosophers is a single chopstick

• Each philosopher has a bowl of rice

39

Page 48: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The dining philosophers

• Philosophers alternate between thinking and eating

• The life of a philosopher• Thinks for a bit• Becomes hungry• Grabs chopstick on their left• Grabs chopstick on their right• Eats some rice• Puts chopsticks down• Goes back to thinking

40

Page 49: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The dining philosophers

• Philosophers alternate between thinking and eating

• The life of a philosopher• Thinks for a bit• Becomes hungry• Grabs chopstick on their left• Grabs chopstick on their right• Eats some rice• Puts chopsticks down• Goes back to thinking

40

they all do the same thing…

Page 50: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The dining philosophers

• Philosophers alternate between thinking and eating

• The life of a philosopher• Thinks for a bit• Becomes hungry• Grabs chopstick on their left• Grabs chopstick on their right• Eats some rice• Puts chopsticks down• Goes back to thinking

40

grabbing both at the same time is too complicated

Page 51: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

The dining philosophers

• Philosophers alternate between thinking and eating

• The life of a philosopher• Thinks for a bit• Becomes hungry• Grabs chopstick on their left• Grabs chopstick on their right• Eats some rice• Puts chopsticks down• Goes back to thinking

41

Philosopher won't go back to thinking until she's eaten

Page 52: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

42

The dining philosophers problem

• The philosophers are:• Too polite to steal chopsticks from each other• Too stubborn to put a chopstick down if they

haven't eaten yet

• Suppose every philosopher grabs their left chopstick at the same time

• What happens?

Page 53: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

42

The dining philosophers problem

• The philosophers are:• Too polite to steal chopsticks from each other• Too stubborn to put a chopstick down if they

haven't eaten yet

• Suppose every philosopher grabs their left chopstick at the same time

• What happens?

• Deadlock! Our poor philosophers starve since they're all waiting for their right chopsticks to become free and stubbornly holding on to their left ones

Page 54: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

43

Page 55: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Homework 6

• Your task on Homework 6 is to code up the dining philosophers problem

• Each philosopher will be one thread

• The chopsticks will be shared state

• You will need to ensure that at most one philosopher holds a given chopstick at any given time

44

Page 56: CSE 399-004: Python Programmingcse39904/lectures/06-WithThreads.pdf•Python's with-statement provides a mechanism for ensuring that "clean-up" actions always get called The with-statement

Future lecture topics

45

• Networking

• Graphical user interfaces

• Functional programming in Python

• And others…?