举例讲解Python编程中对线程锁的使用
锁
python的内置数据结构比如列表和字典等是线程安全的,但是简单数据类型比如整数和浮点数则不是线程安全的,要这些简单数据类型的通过操作,就需要使用锁。
#!/usr/bin/envpython3
#coding=utf-8
importthreading
shared_resource_with_lock=0
shared_resource_with_no_lock=0
COUNT=100000
shared_resource_lock=threading.Lock()
####LOCKMANAGEMENT##
defincrement_with_lock():
globalshared_resource_with_lock
foriinrange(COUNT):
shared_resource_lock.acquire()
shared_resource_with_lock+=1
shared_resource_lock.release()
defdecrement_with_lock():
globalshared_resource_with_lock
foriinrange(COUNT):
shared_resource_lock.acquire()
shared_resource_with_lock-=1
shared_resource_lock.release()
####NOLOCKMANAGEMENT##
defincrement_without_lock():
globalshared_resource_with_no_lock
foriinrange(COUNT):
shared_resource_with_no_lock+=1
defdecrement_without_lock():
globalshared_resource_with_no_lock
foriinrange(COUNT):
shared_resource_with_no_lock-=1
####theMainprogram
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("thevalueofsharedvariablewithlockmanagementis%s"\
%shared_resource_with_lock)
print("thevalueofsharedvariablewithraceconditionis%s"\
%shared_resource_with_no_lock)
执行结果:
$./threading_lock.py
thevalueofsharedvariablewithlockmanagementis0 thevalueofsharedvariablewithraceconditionis0
又如:
importrandom
importthreading
importtime
logging.basicConfig(level=logging.DEBUG,
format='(%(threadName)-10s)%(message)s',
)
classCounter(object):
def__init__(self,start=0):
self.lock=threading.Lock()
self.value=start
defincrement(self):
logging.debug(time.ctime(time.time()))
logging.debug('Waitingforlock')
self.lock.acquire()
try:
pause=random.randint(1,3)
logging.debug(time.ctime(time.time()))
logging.debug('Acquiredlock')
self.value=self.value+1
logging.debug('lock{0}seconds'.format(pause))
time.sleep(pause)
finally:
self.lock.release()
defworker(c):
foriinrange(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()
foriinrange(2):
t=threading.Thread(target=worker,args=(counter,))
t.start()
logging.debug('Waitingforworkerthreads')
main_thread=threading.currentThread()
fortinthreading.enumerate():
iftisnotmain_thread:
t.join()
logging.debug('Counter:%d',counter.value)
执行结果:
$pythonthreading_lock.py
(Thread-1)TueSep1515:49:182015 (Thread-1)Sleeping3.00 (Thread-2)TueSep1515:49:182015 (MainThread)Waitingforworkerthreads (Thread-2)Sleeping2.00 (Thread-2)TueSep1515:49:202015 (Thread-2)Waitingforlock (Thread-2)TueSep1515:49:202015 (Thread-2)Acquiredlock (Thread-2)lock2seconds (Thread-1)TueSep1515:49:212015 (Thread-1)Waitingforlock (Thread-2)TueSep1515:49:222015 (Thread-1)TueSep1515:49:222015 (Thread-2)Sleeping2.00 (Thread-1)Acquiredlock (Thread-1)lock1seconds (Thread-1)TueSep1515:49:232015 (Thread-1)Sleeping2.00 (Thread-2)TueSep1515:49:242015 (Thread-2)Waitingforlock (Thread-2)TueSep1515:49:242015 (Thread-2)Acquiredlock (Thread-2)lock1seconds (Thread-1)TueSep1515:49:252015 (Thread-1)Waitingforlock (Thread-1)TueSep1515:49:252015 (Thread-1)Acquiredlock (Thread-1)lock2seconds (Thread-2)Done (Thread-1)Done (MainThread)Counter:4
acquire()中传入False值,可以检查是否获得了锁。比如:
importlogging
importthreading
importtime
logging.basicConfig(level=logging.DEBUG,
format='(%(threadName)-10s)%(message)s',
)
deflock_holder(lock):
logging.debug('Starting')
whileTrue:
lock.acquire()
try:
logging.debug('Holding')
time.sleep(0.5)
finally:
logging.debug('Notholding')
lock.release()
time.sleep(0.5)
return
defworker(lock):
logging.debug('Starting')
num_tries=0
num_acquires=0
whilenum_acquires<3:
time.sleep(0.5)
logging.debug('Tryingtoacquire')
have_it=lock.acquire(0)
try:
num_tries+=1
ifhave_it:
logging.debug('Iteration%d:Acquired',
num_tries)
num_acquires+=1
else:
logging.debug('Iteration%d:Notacquired',
num_tries)
finally:
ifhave_it:
lock.release()
logging.debug('Doneafter%diterations',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()
执行结果:
$pythonthreading_lock_noblock.py
(LockHolder)Starting (LockHolder)Holding (Worker)Starting (LockHolder)Notholding (Worker)Tryingtoacquire (Worker)Iteration1:Acquired (LockHolder)Holding (Worker)Tryingtoacquire (Worker)Iteration2:Notacquired (LockHolder)Notholding (Worker)Tryingtoacquire (Worker)Iteration3:Acquired (LockHolder)Holding (Worker)Tryingtoacquire (Worker)Iteration4:Notacquired (LockHolder)Notholding (Worker)Tryingtoacquire (Worker)Iteration5:Acquired (Worker)Doneafter5iterations
线程安全锁
threading.RLock()
返回可重入锁对象。重入锁必须由获得它的线程释放。一旦线程获得了重入锁,同一线程可不阻塞地再次获得,获取之后必须释放。
通常一个线程只能获取一次锁:
importthreading lock=threading.Lock() print'Firsttry:',lock.acquire() print'Secondtry:',lock.acquire(0)
执行结果:
$pythonthreading_lock_reacquire.py
Firsttry:True Secondtry:False
使用RLock可以获取多次锁:
importthreading lock=threading.RLock() print'Firsttry:',lock.acquire() print'Secondtry:',lock.acquire(0)
执行结果:
pythonthreading_rlock.py
Firsttry:True Secondtry:1
再来看一个例子:
#!/usr/bin/envpython3
#coding=utf-8
importthreading
importtime
classBox(object):
lock=threading.RLock()
def__init__(self):
self.total_items=0
defexecute(self,n):
Box.lock.acquire()
self.total_items+=n
Box.lock.release()
defadd(self):
Box.lock.acquire()
self.execute(1)
Box.lock.release()
defremove(self):
Box.lock.acquire()
self.execute(-1)
Box.lock.release()
##Thesetwofunctionsrunninseparate
##threadsandcalltheBox'smethods
defadder(box,items):
whileitems>0:
print("adding1iteminthebox\n")
box.add()
time.sleep(5)
items-=1
defremover(box,items):
whileitems>0:
print("removing1iteminthebox")
box.remove()
time.sleep(5)
items-=1
##themainprogrambuildsome
##threadsandmakesureitworks
if__name__=="__main__":
items=5
print("putting%sitemsinthebox"%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("%sitemsstillremaininthebox"%box.total_items)
执行结果:
$python3threading_rlock2.py
putting5itemsinthebox adding1iteminthebox removing1iteminthebox adding1iteminthebox removing1iteminthebox adding1iteminthebox removing1iteminthebox removing1iteminthebox adding1iteminthebox removing1iteminthebox adding1iteminthebox 0itemsstillremaininthebox