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


Posted in Python onJuly 12, 2016

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
Python 相关文章推荐
简单介绍Ruby中的CGI编程
Apr 10 Python
python通过定义一个类实例作为ftp回调方法
May 04 Python
python socket多线程通讯实例分析(聊天室)
Apr 06 Python
python实现机械分词之逆向最大匹配算法代码示例
Dec 13 Python
使用python实现ANN
Dec 20 Python
python 矩阵增加一行或一列的实例
Apr 04 Python
python实现简单登陆系统
Oct 18 Python
pandas分区间,算频率的实例
Jul 04 Python
Django MEDIA的配置及用法详解
Jul 25 Python
Python使用scrapy爬取阳光热线问政平台过程解析
Aug 14 Python
python print 格式化输出,动态指定长度的实现
Apr 12 Python
Python学习工具jupyter notebook安装及用法解析
Oct 23 Python
使用Python编写一个最基础的代码解释器的要点解析
Jul 12 #Python
Python中使用bidict模块双向字典结构的奇技淫巧
Jul 12 #Python
Python使用SocketServer模块编写基本服务器程序的教程
Jul 12 #Python
使用Python的Flask框架表单插件Flask-WTF实现Web登录验证
Jul 12 #Python
Python的Flask框架标配模板引擎Jinja2的使用教程
Jul 12 #Python
深度定制Python的Flask框架开发环境的一些技巧总结
Jul 12 #Python
Python的面向对象编程方式学习笔记
Jul 12 #Python
You might like
新页面打开实际尺寸的图片
2006/08/25 Javascript
用javascript实现无刷新更新数据的详细步骤 asp
2006/12/26 Javascript
兼容IE、FireFox、Chrome等浏览器的xml处理函数js代码
2011/11/30 Javascript
JavaScript中变量提升 Hoisting
2012/07/03 Javascript
jquery焦点图片切换(数字标注/手动/自动播放/横向滚动)
2013/01/24 Javascript
JavaScript加强之自定义callback示例
2013/09/21 Javascript
JS正则验证邮箱的格式详细介绍
2013/11/19 Javascript
一个js控制的导航菜单实例代码
2013/12/03 Javascript
display和visibility的区别示例介绍
2014/02/26 Javascript
JavaScript html5 canvas画布中删除一个块区域的方法
2016/01/26 Javascript
jQuery新窗口打开外链接
2016/07/21 Javascript
浅谈jQuery中的$.extend方法来扩展JSON对象
2017/02/12 Javascript
jQuery给表格添加分页效果
2017/03/02 Javascript
详解nodejs微信jssdk后端接口
2017/05/25 NodeJs
express如何使用session与cookie的方法
2018/01/30 Javascript
jQuery UI实现动画效果代码分享
2018/08/19 jQuery
小程序视频或音频自定义可拖拽进度条的示例代码
2018/09/30 Javascript
vue中v-for通过动态绑定class实现触发效果
2018/12/06 Javascript
探索JavaScript中私有成员的相关知识
2019/06/13 Javascript
Vue编写可显示周和月模式的日历 Vue自定义日历内容的显示
2019/06/26 Javascript
javascript使用canvas实现饼状图效果
2020/09/08 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
浅析python中SQLAlchemy排序的一个坑
2017/02/24 Python
Python编程产生非均匀随机数的几种方法代码分享
2017/12/13 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
Python 20行简单实现有道在线翻译的详解
2019/05/15 Python
canvas实现烟花的示例代码
2020/01/16 HTML / CSS
澳大利亚第一旅行车和房车配件店:Caravan RV Camping
2020/12/26 全球购物
迪卡侬波兰体育用品商店:Decathlon波兰
2020/03/31 全球购物
简单叙述一下MYSQL的优化
2016/05/09 面试题
大学生活自我评价
2014/04/09 职场文书
母校寄语大全
2014/04/10 职场文书
五五普法心得体会
2014/09/04 职场文书
挂职学习心得体会
2014/09/09 职场文书
工资收入证明样本(5篇)
2014/09/16 职场文书
财务人员岗位职责
2015/02/03 职场文书