VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • Python3标准库:threading进程中管理并发操作(5)

debug('Counter: %d', counter.value)

在这个例子中,worker()函数使一个Counter实例递增,这个实例管理着一个Lock,以避免两个线程同时改变其内部状态。如果没有使用Lock,就有可能丢失一次对value属性的修改。

要确定是否有另一个线程请求这个锁而不影响当前线程,可以向acquire()的blocking参数传入False。在下一个例子中,worker()想要分别得到3次锁,并统计为得到锁而尝试的次数。与此同时,lock_holder()在占有和释放锁之间循环,每个状态会短暂暂停,以模拟负载情况。


	
  1. import logging
  2. import threading
  3. import time
  4.  
  5. def lock_holder(lock):
  6. logging.debug('Starting')
  7. while True:
  8. lock.acquire()
  9. try:
  10. logging.debug('Holding')
  11. time.sleep(0.5)
  12. finally:
  13. logging.debug('Not holding')
  14. lock.release()
  15. time.sleep(0.5)
  16.  
  17. def worker(lock):
  18. logging.debug('Starting')
  19. num_tries = 0
  20. num_acquires = 0
  21. while num_acquires < 3:
  22. time.sleep(0.5)
  23. logging.debug('Trying to acquire')
  24. have_it = lock.acquire(0)
  25. try:
  26. num_tries += 1
  27. if have_it:
  28. logging.debug('Iteration %d: Acquired',
  29. num_tries)
  30. num_acquires += 1
  31. else:
  32. logging.debug('Iteration %d: Not acquired',
  33. num_tries)
  34. finally:
  35. if have_it:
  36. lock.release()
  37. logging.debug('Done after %d iterations', num_tries)
  38.  
  39. logging.basicConfig(
  40. level=logging.DEBUG,
  41. format='(%(threadName)-10s) %(message)s',
  42. )
  43.  
  44. lock = threading.Lock()
  45.  
  46. holder = threading.Thread(
  47. target=lock_holder,
  48. args=(lock,),
  49. name='LockHolder',
  50. daemon=True,
  51. )
  52. holder.start()
  53.  
  54. worker = threading.Thread(
  55. target=worker,
  56. args=(lock,),
  57. name='Worker',
  58. )
  59. worker.start()

worker()需要超过3次迭代才能得到3次锁。

1.8.1 再入锁

正常的Lock对象不能请求多次,即使是由同一个线程请求也不例外。如果同一个调用链中的多个函数访问一个锁,则可能会产生我们不希望的副作用。


	
  1. import threading
  2.  
  3. lock = threading.Lock()
  4.  
  5. print('First try :', lock.acquire())
  6. print('Second try:', lock.acquire(0))

在这里,对第二个acquire()调用给定超时值为0,以避免阻塞,因为锁已经被第一个调用获得。

如果同一个线程的不同代码需要"重新获得"锁,那么在这种情况下要使用RLock。


	
  1. import threading
  2.  
  3. lock = threading.RLock()
  4.  
  5. print('First try :', lock.acquire())
  6. print('Second try:', lock.acquire(0))

与前面的例子相比,对代码唯一的修改就是用RLock替换Lock。

1.8.2 锁作为上下文管理器

锁实现了上下文管理器API,并与with语句兼容。使用with则不再需要显式地获得和释放锁。


	
  1. import threading
  2. import logging
  3.  
  4. def worker_with(lock):
  5. with lock:
  6. logging.debug('Lock acquired via with')
  7.  
  8. def worker_no_with(lock):
  9. lock.acquire()
  10. try:
  11. logging.debug('Lock acquired directly')
  12. finally:
  13. lock.release()
  14.  
  15. logging.basicConfig(
  16. level=logging.DEBUG,
  17. format=

相关教程