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和shell变量互相传递的几种方法
Nov 20 Python
python通过线程实现定时器timer的方法
Mar 16 Python
python使用标准库根据进程名如何获取进程的pid详解
Oct 31 Python
Python3调用微信企业号API发送文本消息代码示例
Nov 10 Python
Python实现的随机森林算法与简单总结
Jan 30 Python
基于DataFrame筛选数据与loc的用法详解
May 18 Python
Python SQL查询并生成json文件操作示例
Aug 17 Python
pycharm重置设置,恢复默认设置的方法
Oct 22 Python
python和mysql交互操作实例详解【基于pymysql库】
Jun 04 Python
python爬虫项目设置一个中断重连的程序的实现
Jul 26 Python
Python简易计算器制作方法代码详解
Oct 31 Python
python3 配置logging日志类的操作
Apr 08 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获取post中的json数据的实现方法
2011/06/08 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
2019/02/28 PHP
PHP面向对象程序设计模拟一般面向对象语言中的方法重载(overload)示例
2019/06/13 PHP
改进版通过Json对象实现深复制的方法
2012/10/24 Javascript
jquery获取div宽度的实现思路与代码
2013/01/13 Javascript
JQuery动画与特效实例分析
2015/02/02 Javascript
jquery 插件实现多行文本框[textarea]自动高度
2015/03/04 Javascript
Bootstrap3学习笔记(二)之排版
2016/05/20 Javascript
vue 系列——vue2-webpack2框架搭建踩坑之路
2017/12/22 Javascript
Vue Cli 3项目使用融云IM实现聊天功能的方法
2019/04/19 Javascript
在layui下对元素进行事件绑定的实例
2019/09/06 Javascript
js实现图片3D轮播效果
2019/09/21 Javascript
vue 自定义组件的写法与用法详解
2020/03/04 Javascript
JS数据类型(基本数据类型、引用数据类型)及堆和栈的区别分析
2020/03/04 Javascript
JavaScript常用进制转换及位运算实例解析
2020/10/14 Javascript
antd多选下拉框一行展示的实现方式
2020/10/31 Javascript
vue3.0中使用element的完整步骤
2021/03/04 Vue.js
[16:19]教你分分钟做大人——风暴之灵
2015/03/11 DOTA
几个提升Python运行效率的方法之间的对比
2015/04/03 Python
python实现多线程的两种方式
2016/05/22 Python
pandas数据清洗,排序,索引设置,数据选取方法
2018/05/18 Python
python 统计列表中不同元素的数量方法
2018/06/29 Python
解决Python一行输出不显示的问题
2018/12/03 Python
Python3调用百度AI识别图片中的文字功能示例【测试可用】
2019/03/13 Python
Clarks其乐鞋荷兰官网:Clarks荷兰
2019/07/05 全球购物
党校自我鉴定范文
2013/10/02 职场文书
心碎乌托邦的创业计划书范文
2013/12/26 职场文书
公司门卫管理制度
2014/02/01 职场文书
《鸿门宴》教学反思
2014/04/22 职场文书
计划生育证明格式范本
2014/09/12 职场文书
群众路线教育实践活动心得体会(四风)
2014/11/03 职场文书
2014年企业员工工作总结
2014/12/09 职场文书
房产公证书样本
2015/01/23 职场文书
2015年清明节演讲稿范文
2015/03/17 职场文书
恶魔之树最顶端的三颗果实 震震果实上榜,第一可以制造岩浆
2022/03/18 日漫
MSSQL基本语法操作
2022/04/11 SQL Server