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的Flask框架中Flask-Admin库的简单入门指引
Apr 07 Python
python获取外网ip地址的方法总结
Jul 02 Python
python生成随机密码或随机字符串的方法
Jul 03 Python
python实现JAVA源代码从ANSI到UTF-8的批量转换方法
Aug 10 Python
详解设计模式中的工厂方法模式在Python程序中的运用
Mar 02 Python
Python实现mysql数据库更新表数据接口的功能
Nov 19 Python
Python解析命令行读取参数--argparse模块使用方法
Jan 23 Python
python 梯度法求解函数极值的实例
Jul 10 Python
纯python进行矩阵的相乘运算的方法示例
Jul 17 Python
在python image 中安装中文字体的实现方法
Aug 22 Python
Pandas之缺失数据的实现
Jan 06 Python
详细介绍python操作RabbitMq
Apr 12 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正则提取或替换img标记属性
2013/06/26 PHP
Laravel5中contracts详解
2015/03/02 PHP
PHP CURL使用详解
2019/03/21 PHP
jQuery选中select控件 无法设置selected的解决方法
2010/09/01 Javascript
仅IE6/7/8中innerHTML返回值忽略英文空格的问题
2011/04/07 Javascript
jQuery图片播放8款精美插件分享
2013/02/17 Javascript
用JQuery 判断某个属性是否存在hasAttr的解决方法
2013/04/26 Javascript
点击按钮或链接不跳转只刷新页面的脚本整理
2013/10/22 Javascript
3分钟写出来的Jquery版checkbox全选反选功能
2013/10/23 Javascript
jquery批量设置属性readonly和disabled的方法
2014/01/24 Javascript
Javascript实现飞动广告效果的方法
2015/05/25 Javascript
jQuery动态创建元素以及追加节点的实现方法
2016/10/20 Javascript
js实现兼容PC端和移动端滑块拖动选择数字效果
2017/02/16 Javascript
通俗易懂地解释JS中的闭包
2017/10/23 Javascript
vue :src 文件路径错误问题的解决方法
2018/05/15 Javascript
vue-cli 首屏加载优化问题
2018/11/06 Javascript
jQuery动态生成的元素绑定事件操作实例分析
2019/05/04 jQuery
js使用文件流下载csv文件的实现方法
2019/07/15 Javascript
javascript实现动态时钟的启动和停止
2020/07/29 Javascript
浅谈Vue.use到底是什么鬼
2020/01/21 Javascript
[59:35]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#1COL VS Alliance第二局
2016/03/04 DOTA
[15:20]DOTA2-DPC中国联赛 正赛 Elephant vs Aster 选手采访
2021/03/11 DOTA
Python实现字符串匹配算法代码示例
2017/12/05 Python
Python实现全排列的打印
2018/08/18 Python
python mac下安装虚拟环境的图文教程
2019/04/12 Python
在django view中给form传入参数的例子
2019/07/19 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
2020/01/06 Python
Pytorch 实现sobel算子的卷积操作详解
2020/01/10 Python
Tensorflow分批量读取数据教程
2020/02/07 Python
事业单位考核材料
2014/05/21 职场文书
冬季安全检查方案
2014/05/23 职场文书
领导班子“四风问题”“整改方案
2014/10/02 职场文书
2014学生会工作总结报告
2014/12/02 职场文书
孝老爱亲事迹材料
2014/12/24 职场文书
本溪关门山导游词
2015/02/09 职场文书
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript