Python线程同步的实现代码


Posted in Python onOctober 03, 2018

本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块。

threading 模块提供的线程同步原语包括:Lock、RLock、Condition、Event、Semaphore等对象。

线程执行

join与setDaemon

子线程在主线程运行结束后,会继续执行完,如果给子线程设置为守护线程(setDaemon=True),主线程运行结束子线程即结束;

如果join()线程,那么主线程会等待子线程执行完再执行。

import threading
import time


def get_thread_a():
 print("get thread A started")
 time.sleep(3)
 print("get thread A end")


def get_thread_b():
 print("get thread B started")
 time.sleep(5)
 print("get thread B end")


if __name__ == "__main__":
 thread_a = threading.Thread(target=get_thread_a)
 thread_b = threading.Thread(target=get_thread_b)
 start_time = time.time()
 thread_b.setDaemon(True)
 thread_a.start()
 thread_b.start()
 thread_a.join()
 
 end_time = time.time()
 print("execution time: {}".format(end_time - start_time))

thread_a是join,首先子线程thread_a执行,thread_b是守护线程,当主线程执行完后,thread_b不会再执行执行结果如下:

get thread A started
get thread B started
get thread A end
execution time: 3.003199815750122

线程同步

当线程间共享全局变量,多个线程对该变量执行不同的操作时,该变量最终的结果可能是不确定的(每次线程执行后的结果不同),如:对count变量执行加减操作 ,count的值是不确定的,要想count的值是一个确定的需对线程执行的代码段加锁。

python对线程加锁主要有Lock和Rlock模块

Lock: 

from threading import Lock
lock = Lock()
lock.acquire()
lock.release()

Lock有acquire()和release()方法,这两个方法必须是成对出现的,acquire()后面必须release()后才能再acquire(),否则会造成死锁

Rlock:

鉴于Lock可能会造成死锁的情况,RLock(可重入锁)对Lock进行了改进,RLock可以在同一个线程里面连续调用多次acquire(),但必须再执行相同次数的release()

from threading import RLock
lock = RLock()
lock.acquire()
lock.acquire()
lock.release()
lock.release()

condition(条件变量),线程在执行时,当满足了特定的条件后,才可以访问相关的数据

import threading

def get_thread_a(condition):
 with condition:
  condition.wait()
  print("A : Hello B,that's ok")
  condition.notify()
  condition.wait()
  print("A : I'm fine,and you?")
  condition.notify()
  condition.wait()
  print("A : Nice to meet you")
  condition.notify()
  condition.wait()
  print("A : That's all for today")
  condition.notify()

def get_thread_b(condition):
 with condition:
  print("B : Hi A, Let's start the conversation")
  condition.notify()
  condition.wait()
  print("B : How are you")
  condition.notify()
  condition.wait()
  print("B : I'm fine too")
  condition.notify()
  condition.wait()
  print("B : Nice to meet you,too")
  condition.notify()
  condition.wait()
  print("B : Oh,goodbye")

if __name__ == "__main__":
 condition = threading.Condition()
 thread_a = threading.Thread(target=get_thread_a, args=(condition,))
 thread_b = threading.Thread(target=get_thread_b, args=(condition,))
 thread_a.start()
 thread_b.start()

Condition内部有一把锁,默认是RLock,在调用wait()和notify()之前必须先调用acquire()获取这个锁,才能继续执行;当wait()和notify()执行完后,需调用release()释放这个锁,在执行with condition时,会先执行acquire(),with结束时,执行了release();所以condition有两层锁,最底层锁在调用wait()时会释放,同时会加一把锁到等待队列,等待notify()唤醒释放锁

wait() :允许等待某个条件变量的通知,notify()可唤醒

notify(): 唤醒等待队列wait()

执行结果:

B : Hi A, Let's start the conversation
A : Hello B,that's ok
B : How are you
A : I'm fine,and you?
B : I'm fine too
A : Nice to meet you
B : Nice to meet you,too
A : That's all for today
B : Oh,goodbye

Semaphore(信号量)

用于控制线程的并发数,如爬虫中请求次数过于频繁会被禁止ip,每次控制爬取网页的线程数量可在一定程度上防止ip被禁;文件读写中,控制写线程每次只有一个,读线程可多个。

import time
import threading


def get_thread_a(semaphore,i):
 time.sleep(1)
 print("get thread : {}".format(i))
 semaphore.release()


def get_thread_b(semaphore):
 for i in range(10):
  semaphore.acquire()
  thread_a = threading.Thread(target=get_thread_a, args=(semaphore,i))
  thread_a.start()


if __name__ == "__main__":
 semaphore = threading.Semaphore(2)
 thread_b = threading.Thread(target=get_thread_b, args=(semaphore,))
 thread_b.start()

上述示例了每隔1秒并发两个线程执行的情况,当调用一次semaphore.acquire()时,Semaphore的数量就减1,直至Semaphore数量为0时被锁上,当release()后Semaphore数量加1。Semaphore在本质上是调用的Condition,semaphore.acquire()在Semaphore的值为0的条件下会调用Condition.wait(), 否则将值减1,semaphore.release()会将Semaphore的值加1,并调用Condition.notify()

Semaphore源码

def acquire(self, blocking=True, timeout=None):
  if not blocking and timeout is not None:
   raise ValueError("can't specify timeout for non-blocking acquire")
  rc = False
  endtime = None
  with self._cond:
   while self._value == 0:
    if not blocking:
     break
    if timeout is not None:
     if endtime is None:
      endtime = _time() + timeout
     else:
      timeout = endtime - _time()
      if timeout <= 0:
       break
    self._cond.wait(timeout)
   else:
    self._value -= 1
    rc = True
  return rc

def release(self):
  with self._cond:
   self._value += 1
   self._cond.notify()

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python使用pylab库实现绘制直方图功能示例
Jun 01 Python
Python实用技巧之列表、字典、集合中根据条件筛选数据详解
Jul 11 Python
详解Python Qt的窗体开发的基本操作
Jul 14 Python
使用 Python 快速实现 HTTP 和 FTP 服务器的方法
Jul 22 Python
Python实现微信机器人的方法
Sep 06 Python
Python +Selenium解决图片验证码登录或注册问题(推荐)
Feb 09 Python
Python面向对象程序设计之静态方法、类方法、属性方法原理与用法分析
Mar 23 Python
python属于跨平台语言码
Jun 09 Python
Python实现像awk一样分割字符串
Sep 15 Python
python 下划线的不同用法
Oct 24 Python
pandas:get_dummies()与pd.factorize()的用法及区别说明
May 21 Python
python如何将mat文件转为png
Jul 15 Python
详解通过API管理或定制开发ECS实例
Sep 30 #Python
Python 使用类写装饰器的小技巧
Sep 30 #Python
浅谈django三种缓存模式的使用及注意点
Sep 30 #Python
使用Python实现租车计费系统的两种方法
Sep 29 #Python
Python实现App自动签到领取积分功能
Sep 29 #Python
10个Python小技巧你值得拥有
Sep 29 #Python
实例分析python3实现并发访问水平切分表
Sep 29 #Python
You might like
PHP实现获取中英文首字母
2015/06/19 PHP
PHP面试题之文件目录操作
2015/10/15 PHP
jQuery不间断滚动效果(模拟百度新闻支持文字/图片/垂直滚动)
2013/02/05 Javascript
网页运行时提示对象不支持abigimage属性或方法
2014/08/10 Javascript
使用nodejs开发cli项目实例
2015/06/03 NodeJs
跟我学习javascript的定时器
2015/11/19 Javascript
JQuery用户名校验的具体实现
2016/03/18 Javascript
jQuery遍历DOM元素与节点方法详解
2016/04/14 Javascript
JavaScript生成.xls文件的代码
2016/12/22 Javascript
基于Bootstrap 3 JQuery及RegExp的表单验证功能
2017/02/16 Javascript
js实现华丽的九九乘法表效果
2017/03/29 Javascript
JavaScript的console命令使用实例
2019/12/03 Javascript
Vue v-model组件封装(类似弹窗组件)
2020/01/08 Javascript
深入理解Javascript中的this关键字
2015/03/27 Python
python中zip()方法应用实例分析
2016/04/16 Python
Python内置类型性能分析过程实例
2020/01/29 Python
opencv python图像梯度实例详解
2020/02/04 Python
Pytorch使用PIL和Numpy将单张图片转为Pytorch张量方式
2020/05/25 Python
Keras 切换后端方式(Theano和TensorFlow)
2020/06/19 Python
CSS的background属性及CSS3的背景图片设置总结
2016/06/13 HTML / CSS
不开辟用于交换数据的临时空间,如何完成字符串的逆序
2012/12/02 面试题
如何防止同一个帐户被多人同时登录
2013/08/01 面试题
UNIX特点都有哪些
2016/04/05 面试题
详解如何解决使用JSON.stringify时遇到的循环引用问题
2021/03/23 Javascript
优秀应届生推荐信
2013/11/09 职场文书
高中政治教学反思
2014/01/18 职场文书
药店促销活动总结
2014/07/10 职场文书
2014党的群众路线教育实践活动总结材料
2014/10/31 职场文书
2014年连锁店圣诞节活动方案
2014/12/09 职场文书
教师思想工作总结2015
2015/05/13 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
幼儿园托班教育随笔
2015/08/14 职场文书
2016年教师寒假学习心得体会
2015/10/09 职场文书
《秋天的雨》教学反思
2016/02/19 职场文书
oracle DGMGRL ORA-16603报错的解决方法(DG Broker)
2021/04/06 Oracle
Python+Matplotlib+LaTeX玩转数学公式
2022/02/24 Python