详解python多线程之间的同步(一)


Posted in Python onApril 03, 2019

引言:

线程之间经常需要协同工作,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直到该线程完成对数据的操作。这些技术包括临界区(Critical Section),互斥量(Mutex),信号量(Semaphore),事件Event等。

Event

 threading库中的event对象通过使用内部一个flag标记,通过flag的True或者False的变化来进行操作。

     名称                                      含义
set( ) 标记设置为True
clear( ) 标记设置为False
is_set( ) 标记是否为True
wait(timeout=None) 设置等待标记为True的时长,None为无限等待。等到返回True,等不到返回False
from threading import Thread,Event
import time

def creditor(event:Event):
 print("什么时候还我钱")
 event.wait()
 print("我已经等了很长时间了")


def debtor(event:Event,count=10):
 print("可以宽裕几天吗?")
 money=[]
 while True:
 print("先还你100")
 time.sleep(0.5)
 money.append(1)
 if len(money)>count:
  event.set()
  break
 print("我已经还完你的钱了")

event=Event()
c=Thread(target=creditor,args=(event,))
d=Thread(target=debtor,args=(event,))
c.start()
d.start()

运行结果如下所示:

详解python多线程之间的同步(一)

可以看到creditor函数中因为event.wait( )线程进入等待状态,此时debtor线程进入运行,当满足条件时event.set( )将标记设置为True,creditor线程开始运行。谁wait就是等到flag变为True,或等到超时变为False。不限制等待的个数。

wait的使用

from threading import Event,Thread


def Wait(event:Event,interval):
 while not event.wait(interval):
 print("waiting for you")

e=Event()
Thread(target=Wait,args=(e,3)).start()
e.wait(10)
e.set()
print("main exit")

详解python多线程之间的同步(一)

主线程一开始就wait 10s,Waiting线程等待3s返回False,进入循环打印"waiting for you",重复3次,然后主线程set了,这时候Waiting线程变为True,不再进入循环。

Lock

凡是存在资源争用的地方都可以使用锁,从而保证只有一个使用者可以完全使用这个资源

现在要生产10个杯子,由10个工人开始生产

import threading
import time 

cups=[]

def worker(count=10):
 print("我是{},我开始生产了".format(threading.current_thread().name))
 flag=False
 while True:
 if len(cups)>count:
  flag=True
 time.sleep(0.05)
 if not flag:
  cups.append(1)
 if flag:
  break 
 print("finished.cups={}".format(len(cups)))
 
for _ in range(10):
 threading.Thread(target=worker,args=(1000,)).start()

运行结果如下图所示:

详解python多线程之间的同步(一)

我们明明只需要到1000就会break,但是结果却到了1010个,这就是因为有10个线程,其中每个线程都在增加,但是增加后的数目,其他线程并不会知道(每个线程通过len函数拿到数量,但是刚拿到数字,其他线程就立即更新了)

这个时候我们就需要锁lock来实现了,一旦线程获得锁,其他试图获取锁的线程将被阻塞

      名称                                含义
acquire(blocking=True,timeout=-1) 默认阻塞,阻塞可以设置超时时间。非阻塞时,timeout禁止设置。成功获取锁,返回True,否则返回False
release( ) 释放锁。可以从任何线程释放。已上锁的锁,会抛出RuntimeError异常

加锁的实现:

import threading 
import time 

cups=[]
lock=threading.Lock()

def worker(count=10):
 print("我是{},我开始生产了".format(threading.current_thread().name))
 flag=False
 while True:
 lock.acquire()
 if len(cups)>=count:
  flag=True
 time.sleep(0.005)
 if not flag:
  cups.append(1)
 lock.release()
 if flag:
  break
 print("finished,cups={}".format(len(cups)))
 
for _ in range(10):
 threading.Thread(target=worker,args=(1000,)).start()

运行结果如图所示:

详解python多线程之间的同步(一)

一般来说加锁后还需要一些代码实现,在释放锁之前还有可能抛出异常,一旦出现异常,锁无法释放,但是当前这个线程会因为这个异常而终止,这样会产生死锁,因此使用时要使用如下的方法:

1,使用try...finally语句保证锁的释放

2,with安全上下文管理(锁对象支持上下文管理)

计数器类,用来加,减。

import threading
import time


class Counter:
 def __init__(self):
 self._val = 0
 self.__lock = threading.Lock()

 @property
 def value(self):
 return self._val

 def inc(self):
 try:
  self.__lock.acquire()
  self._val += 1
 finally:
  self.__lock.release()

 def dec(self):
 with self.__lock:
  self._val -= 1


def run(c: Counter, count=100):
 for _ in range(count):
 for i in range(-50, 50):
  if i < 0:
  c.dec()
  else:
  c.inc()


c = Counter()
c1 = 10
c2 = 1000


for i in range(c1):
 threading.Thread(target=run, args=(c, c2)).start()


while True:
 if threading.active_count() == 1:
 print(c.value)
 break

启动了10个线程,1000次从-50到50进行加减,最后得到0,如果没有加锁处理的话,得到的结果未必是自己想要的。

锁的使用场景:

锁适用于访问和修改同一个资源的时候,引起资源争用的情况下。使用锁的注意事项:

  1. 1,少用锁,除非有必要。多线程访问加锁的资源时,由于锁的存在,实际就变成了串行。
  2. 2,加锁时间越短越好,不需要就立即释放锁。
  3. 3,一定要避免死锁,使用with或者try...finally。

非阻塞锁使用

import threading
import time


def worker(tasks):
 for task in tasks:
 time.sleep(0.001)
 if task.lock.acquire(False):
  print("{} {} begin to start".format(threading.current_thread(),task.name))
 else:
  print("{} {} is working".format(threading.current_thread(),task.name))


class Task:
 def __init__(self,name):
 self.name=name
 self.lock=threading.Lock()

tasks=[Task('task-{}'.format(x)) for x in range(10)]

for i in range(5):
 threading.Thread(target=worker,name="worker-{}".format(i),args=(tasks,)).start()

运行结果如下图所示:

详解python多线程之间的同步(一)

总共开启了5个线程,每个线程处理10个任务,因为在if语句里面,task.lock.acquire(False),所以每个线程只有拿到锁是True,其他的线程不会阻塞会返回False。打印"is working"。

以上所述是小编给大家介绍的python多线程之间的同步详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python提取内容关键词的方法
Mar 16 Python
再谈Python中的字符串与字符编码(推荐)
Dec 14 Python
python 数据清洗之数据合并、转换、过滤、排序
Feb 12 Python
Windows下PyCharm安装图文教程
Aug 27 Python
在win10和linux上分别安装Python虚拟环境的方法步骤
May 09 Python
python lxml中etree的简单应用
May 10 Python
python 负数取模运算实例
Jun 03 Python
Python 如何查找特定类型文件
Aug 17 Python
Python collections.deque双边队列原理详解
Oct 05 Python
利用python 下载bilibili视频
Nov 13 Python
python绘图pyecharts+pandas的使用详解
Dec 13 Python
解决python 输出到csv 出现多空行的情况
Mar 24 Python
Python将列表数据写入文件(txt, csv,excel)
Apr 03 #Python
详解python读取image
Apr 03 #Python
Python小白必备的8个最常用的内置函数(推荐)
Apr 03 #Python
查看python安装路径及pip安装的包列表及路径
Apr 03 #Python
元组列表字典(莫烦python基础)
Apr 03 #Python
python3 字符串/列表/元组(str/list/tuple)相互转换方法及join()函数的使用
Apr 03 #Python
Python零基础入门学习之输入与输出
Apr 03 #Python
You might like
PHP 用session与gd库实现简单验证码生成与验证的类方法
2016/11/15 PHP
js资料toString 方法
2007/03/13 Javascript
jQuery学习笔记[1] jQuery中的DOM操作
2010/12/03 Javascript
jquery.boxy弹出框(后隔N秒后自动隐藏/自动跳转)
2013/01/15 Javascript
JavaScript设计模式之外观模式实例
2014/10/10 Javascript
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
分享js粘帖屏幕截图到web页面插件screenshot-paste
2020/08/21 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
2016/07/01 Javascript
浅谈移动端之js touch事件 手势滑动事件
2016/11/07 Javascript
JavaScript正则表达式exec/g实现多次循环用法示例
2017/01/17 Javascript
无循环 JavaScript(map、reduce、filter和find)
2017/04/08 Javascript
详解AngularJS controller调用factory
2017/05/19 Javascript
微信小程序图片横向左右滑动案例
2017/05/19 Javascript
LayerClose弹窗关闭刷新方法
2018/08/17 Javascript
element-ui 时间选择器限制范围的实现(随动)
2019/01/09 Javascript
详解vue或uni-app的跨域问题解决方案
2020/02/21 Javascript
jquery实现两个div中的元素相互拖动的方法分析
2020/04/05 jQuery
OpenLayers3实现测量功能
2020/09/25 Javascript
[40:50]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第四场
2014/05/24 DOTA
Python中用max()方法求最大值的介绍
2015/05/15 Python
CSS3 Notes: -webkit-box-reflect实现倒影的实例
2016/12/08 HTML / CSS
迷你分体式空调:SoGoodToBuy
2018/08/07 全球购物
BookOutlet加拿大:在网上书店购买廉价折扣图书和小说
2018/10/05 全球购物
日本最大美瞳直送网:Morecontact(中文)
2019/04/03 全球购物
销售演讲稿范文
2014/01/08 职场文书
电信营业员自我评价分享
2014/01/17 职场文书
乐观自信演讲稿范文
2014/05/21 职场文书
班风口号
2014/06/18 职场文书
党的群众路线教育实践活动个人剖析材料
2014/10/07 职场文书
党的群众路线教育实践活动督导组工作情况汇报
2014/10/28 职场文书
2014党的群众路线教育实践活动学习心得体会
2014/10/31 职场文书
2016年暑期见闻作文
2015/11/25 职场文书
导游词之潮音寺
2019/09/26 职场文书
pycharm2021激活码使用教程(永久激活亲测可用)
2021/03/30 Python
SQLServer 错误: 15404,无法获取有关 Windows NT 组/用户 WIN-8IVSNAQS8T7\Administrator 的信息
2021/06/30 SQL Server
windows11怎么查看wifi密码? win11查看wifi密码的技巧
2021/11/21 数码科技