举例讲解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