举例讲解python编程中对线程锁的使用

python的内置数据结构比如列表和字典等是线程安全的,但是简单数据类型比如整数和浮点数则不是线程安全的,要这些简单数据类型的通过操作,就需要使用锁。

#!/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)

执行结果:

$ ./threading_lock.py

the value of shared variable with lock management is 0
the value of shared variable with race condition is 0

又如:

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)

执行结果:

$ python threading_lock.py

(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值,可以检查是否获得了锁。比如:

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()

执行结果:

$ python threading_lock_noblock.py

(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

线程安全锁

threading.rlock()

返回可重入锁对象。重入锁必须由获得它的线程释放。一旦线程获得了重入锁,同一线程可不阻塞地再次获得,获取之后必须释放。

通常一个线程只能获取一次锁:

import threading
lock = threading.lock()
print ‘first try :’, lock.acquire()
print ‘second try:’, lock.acquire(0)

执行结果:

$ python threading_lock_reacquire.py

first try : true
second try: false

使用rlock可以获取多次锁:

import threading
lock = threading.rlock()
print ‘first try :’, lock.acquire()
print ‘second try:’, lock.acquire(0)

执行结果:

python threading_rlock.py

first try : true
second try: 1

再来看一个例子:

#!/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)

执行结果:

$ python3 threading_rlock2.py

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

Posted in 未分类

发表评论