python的内置数据结构比如列表和字典等是线程安全的,但是简单数据类型比如整数和浮点数则不是线程安全的,要这些简单数据类型的通过操作,就需要使用锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#!/usr/bin/env python3
# coding=utf-8
import threading
shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 100000
shared_resource_lock = threading.Lock()
####LOCK MANAGEMENT##
def increment_with_lock():
global shared_resource_with_lock
for i in range (COUNT):
shared_resource_lock.acquire()
shared_resource_with_lock + = 1
shared_resource_lock.release()
def decrement_with_lock():
global shared_resource_with_lock
for i in range (COUNT):
shared_resource_lock.acquire()
shared_resource_with_lock - = 1
shared_resource_lock.release()
####NO LOCK MANAGEMENT ##
def increment_without_lock():
global shared_resource_with_no_lock
for i in range (COUNT):
shared_resource_with_no_lock + = 1
def decrement_without_lock():
global shared_resource_with_no_lock
for i in range (COUNT):
shared_resource_with_no_lock - = 1
####the Main program
if __name__ = = "__main__" :
t1 = threading.Thread(target = increment_with_lock)
t2 = threading.Thread(target = decrement_with_lock)
t3 = threading.Thread(target = increment_without_lock)
t4 = threading.Thread(target = decrement_without_lock)
t1.start()
t2.start()
t3.start()
t4.start()
t1.join()
t2.join()
t3.join()
t4.join()
print ( "the value of shared variable with lock management is %s" \
% shared_resource_with_lock)
print ( "the value of shared variable with race condition is %s" \
% shared_resource_with_no_lock)
|
执行结果:
1
|
$ . /threading_lock .py
|
1
2
|
the value of shared variable with lock management is 0
the value of shared variable with race condition is 0
|
又如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
import random
import threading
import time
logging.basicConfig(level = logging.DEBUG,
format = '(%(threadName)-10s) %(message)s' ,
)
class Counter( object ):
def __init__( self , start = 0 ):
self .lock = threading.Lock()
self .value = start
def increment( self ):
logging.debug(time.ctime(time.time()))
logging.debug( 'Waiting for lock' )
self .lock.acquire()
try :
pause = random.randint( 1 , 3 )
logging.debug(time.ctime(time.time()))
logging.debug( 'Acquired lock' )
self .value = self .value + 1
logging.debug( 'lock {0} seconds' . format (pause))
time.sleep(pause)
finally :
self .lock.release()
def worker(c):
for i in range ( 2 ):
pause = random.randint( 1 , 3 )
logging.debug(time.ctime(time.time()))
logging.debug( 'Sleeping %0.02f' , pause)
time.sleep(pause)
c.increment()
logging.debug( 'Done' )
counter = Counter()
for i in range ( 2 ):
t = threading.Thread(target = worker, args = (counter,))
t.start()
logging.debug( 'Waiting for worker threads' )
main_thread = threading.currentThread()
for t in threading. enumerate ():
if t is not main_thread:
t.join()
logging.debug( 'Counter: %d' , counter.value)
|
执行结果:
1
|
$ python threading_lock.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
(Thread-1 ) Tue Sep 15 15:49:18 2015
(Thread-1 ) Sleeping 3.00
(Thread-2 ) Tue Sep 15 15:49:18 2015
(MainThread) Waiting for worker threads
(Thread-2 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 2 seconds
(Thread-1 ) Tue Sep 15 15:49:21 2015
(Thread-1 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:22 2015
(Thread-1 ) Tue Sep 15 15:49:22 2015
(Thread-2 ) Sleeping 2.00
(Thread-1 ) Acquired lock
(Thread-1 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:23 2015
(Thread-1 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Waiting for lock
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Acquired lock
(Thread-1 ) lock 2 seconds
(Thread-2 ) Done
(Thread-1 ) Done
(MainThread) Counter: 4
|
acquire()中传入False值,可以检查是否获得了锁。比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
import logging
import threading
import time
logging.basicConfig(level = logging.DEBUG,
format = '(%(threadName)-10s) %(message)s' ,
)
def lock_holder(lock):
logging.debug( 'Starting' )
while True :
lock.acquire()
try :
logging.debug( 'Holding' )
time.sleep( 0.5 )
finally :
logging.debug( 'Not holding' )
lock.release()
time.sleep( 0.5 )
return
def worker(lock):
logging.debug( 'Starting' )
num_tries = 0
num_acquires = 0
while num_acquires < 3 :
time.sleep( 0.5 )
logging.debug( 'Trying to acquire' )
have_it = lock.acquire( 0 )
try :
num_tries + = 1
if have_it:
logging.debug( 'Iteration %d: Acquired' ,
num_tries)
num_acquires + = 1
else :
logging.debug( 'Iteration %d: Not acquired' ,
num_tries)
finally :
if have_it:
lock.release()
logging.debug( 'Done after %d iterations' , num_tries)
lock = threading.Lock()
holder = threading.Thread(target = lock_holder,
args = (lock,),
name = 'LockHolder' )
holder.setDaemon( True )
holder.start()
worker = threading.Thread(target = worker,
args = (lock,),
name = 'Worker' )
worker.start()
|
执行结果:
1
|
$ python threading_lock_noblock.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
(LockHolder) Starting
(LockHolder) Holding
(Worker ) Starting
(LockHolder) Not holding
(Worker ) Trying to acquire
(Worker ) Iteration 1: Acquired
(LockHolder) Holding
(Worker ) Trying to acquire
(Worker ) Iteration 2: Not acquired
(LockHolder) Not holding
(Worker ) Trying to acquire
(Worker ) Iteration 3: Acquired
(LockHolder) Holding
(Worker ) Trying to acquire
(Worker ) Iteration 4: Not acquired
(LockHolder) Not holding
(Worker ) Trying to acquire
(Worker ) Iteration 5: Acquired
(Worker ) Done after 5 iterations
|
线程安全锁
1
|
threading.RLock()
|
返回可重入锁对象。重入锁必须由获得它的线程释放。一旦线程获得了重入锁,同一线程可不阻塞地再次获得,获取之后必须释放。
通常一个线程只能获取一次锁:
1
2
3
4
5
6
|
import threading
lock = threading.Lock()
print 'First try :' , lock.acquire()
print 'Second try:' , lock.acquire( 0 )
|
执行结果:
1
|
$ python threading_lock_reacquire.py
|
1
2
|
First try : True
Second try: False
|
使用RLock可以获取多次锁:
1
2
3
4
|
import threading
lock = threading.RLock()
print 'First try :' , lock.acquire()
print 'Second try:' , lock.acquire( 0 )
|
执行结果:
1
|
python threading_rlock.py
|
1
2
|
First try : True
Second try: 1
|
再来看一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#!/usr/bin/env python3
# coding=utf-8
import threading
import time
class Box( object ):
lock = threading.RLock()
def __init__( self ):
self .total_items = 0
def execute( self ,n):
Box.lock.acquire()
self .total_items + = n
Box.lock.release()
def add( self ):
Box.lock.acquire()
self .execute( 1 )
Box.lock.release()
def remove( self ):
Box.lock.acquire()
self .execute( - 1 )
Box.lock.release()
## These two functions run n in separate
## threads and call the Box's methods
def adder(box,items):
while items > 0 :
print ( "adding 1 item in the box\n" )
box.add()
time.sleep( 5 )
items - = 1
def remover(box,items):
while items > 0 :
print ( "removing 1 item in the box" )
box.remove()
time.sleep( 5 )
items - = 1
## the main program build some
## threads and make sure it works
if __name__ = = "__main__" :
items = 5
print ( "putting %s items in the box " % items)
box = Box()
t1 = threading.Thread(target = adder,args = (box,items))
t2 = threading.Thread(target = remover,args = (box,items))
t1.start()
t2.start()
t1.join()
t2.join()
print ( "%s items still remain in the box " % box.total_items)
|
执行结果:
1
|
$ python3 threading_rlock2.py
|
1
2
3
4
5
6
7
8
9
10
11
12
|
putting 5 items in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
0 items still remain in the box
|