python线程中同步锁详解


Posted in Python onApril 27, 2018

在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock Rlock Semaphore Event Condition 用来保证线程之间的同步,后者保证访问共享变量的互斥问题

Lock & RLock:互斥锁 用来保证多线程访问共享变量的问题
Semaphore对象:Lock互斥锁的加强版,可以被多个线程同时拥有,而Lock只能被某一个线程同时拥有。
Event对象: 它是线程间通信的方式,相当于信号,一个线程可以给另外一个线程发送信号后让其执行操作。
Condition对象:其可以在某些事件触发或者达到特定的条件后才处理数据

1、Lock(互斥锁)

请求锁定 — 进入锁定池等待 — 获取锁 — 已锁定 — 释放锁

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

构造方法:
Lock()

实例方法:
acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。
release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

if mutex.acquire():
 counter += 1
 print "I am %s, set counter:%s" % (self.name, counter)
  mutex.release()

2、RLock(可重入锁)

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

构造方法:
RLock()

实例方法:
acquire([timeout])/release(): 跟Lock差不多。

3、Semaphore(共享对象访问)

咱们再聊聊Semaphore ,说实话Semaphore是我最晚使用的同步锁,以前类似的实现,是我用Rlock实现的,相对来说有些绕,毕竟Rlock 是需要成对的锁定和开锁的》。。。

Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

直接上代码,我们把semaphore控制为3,也就是说,同时有3个线程可以用这个锁,剩下的线程也之只能是阻塞等待了…

#coding:utf-8
#blog xiaorui.cc
import time
import threading

semaphore = threading.Semaphore(3)

def func():
 if semaphore.acquire():
  for i in range(3):
   time.sleep(1)
   print (threading.currentThread().getName() + '获取锁')
  semaphore.release()
  print (threading.currentThread().getName() + ' 释放锁')


for i in range(5):
 t1 = threading.Thread(target=func)
 t1.start()

4、Event(线程间通信)

Event内部包含了一个标志位,初始的时候为false。
可以使用使用set()来将其设置为true;
或者使用clear()将其从新设置为false;
可以使用is_set()来检查标志位的状态;

另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

import threading
import time

class MyThread(threading.Thread):
 def __init__(self, signal):
  threading.Thread.__init__(self)
  self.singal = signal

 def run(self):
  print "I am %s,I will sleep ..."%self.name
  self.singal.wait()
  print "I am %s, I awake..." %self.name

if __name__ == "__main__":
 singal = threading.Event()
 for t in range(0, 3):
  thread = MyThread(singal)
  thread.start()

 print "main thread sleep 3 seconds... "
 time.sleep(3)

 singal.set()

5、Condition(线程同步)

可以把Condition理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

Condition.wait([timeout]):

wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。

Condition.notify():

唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。

Condition.notify_all()
Condition.notifyAll()

唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

对于Condition有个例子,大家可以观摩下。

from threading import Thread, Condition
import time
import random

queue = []
MAX_NUM = 10
condition = Condition()

class ProducerThread(Thread):
 def run(self):
  nums = range(5)
  global queue
  while True:
   condition.acquire()
   if len(queue) == MAX_NUM:
    print "Queue full, producer is waiting"
    condition.wait()
    print "Space in queue, Consumer notified the producer"
   num = random.choice(nums)
   queue.append(num)
   print "Produced", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


class ConsumerThread(Thread):
 def run(self):
  global queue
  while True:
   condition.acquire()
   if not queue:
    print "Nothing in queue, consumer is waiting"
    condition.wait()
    print "Producer added something to queue and notified the consumer"
   num = queue.pop(0)
   print "Consumed", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


ProducerThread().start()
ConsumerThread().start()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python网络编程实例简析
Sep 26 Python
Python函数可变参数定义及其参数传递方式实例详解
May 25 Python
numpy数组拼接简单示例
Dec 15 Python
python matplotlib画图实例代码分享
Dec 27 Python
Python使用cx_Oracle模块操作Oracle数据库详解
May 07 Python
pyqt5利用pyqtDesigner实现登录界面
Mar 28 Python
CentOS7安装Python3的教程详解
Apr 10 Python
keras实现基于孪生网络的图片相似度计算方式
Jun 11 Python
详解Python中如何将数据存储为json格式的文件
Nov 18 Python
Pycharm Plugins加载失败问题解决方案
Nov 28 Python
python爬虫爬取淘宝商品比价(附淘宝反爬虫机制解决小办法)
Dec 03 Python
python抢购软件/插件/脚本附完整源码
Mar 04 Python
python数字图像处理之高级形态学处理
Apr 27 #Python
python线程池threadpool实现篇
Apr 27 #Python
python数字图像处理之骨架提取与分水岭算法
Apr 27 #Python
python多线程之事件Event的使用详解
Apr 27 #Python
python线程池threadpool使用篇
Apr 27 #Python
Python实现删除时保留特定文件夹和文件的示例
Apr 27 #Python
python中yaml配置文件模块的使用详解
Apr 27 #Python
You might like
php数组中删除元素的实现代码
2012/06/22 PHP
PHP使用mysql_fetch_object从查询结果中获取对象集的方法
2015/03/18 PHP
PHP微信支付结果通知与回调策略分析
2019/01/10 PHP
jquery cookie插件代码类
2009/05/26 Javascript
JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )
2011/02/25 Javascript
js中如何把字符串转化为对象、数组示例代码
2013/07/17 Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
2014/04/07 Javascript
js生成动态表格并为每个单元格添加单击事件的方法
2014/04/14 Javascript
三种动态加载js的jquery实例代码另附去除js方法
2014/04/30 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
整理Javascript数组学习笔记
2015/11/29 Javascript
js判断出两个字符串最大子串的函数实现方法
2016/11/01 Javascript
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
简单实现vue验证码60秒倒计时功能
2017/10/11 Javascript
angularJs-$http实现百度搜索时的动态下拉框示例
2018/02/27 Javascript
Vue与Node.js通过socket.io通信的示例代码
2018/07/25 Javascript
当vue路由变化时,改变导航栏的样式方法
2018/08/22 Javascript
解决vue-cli项目webpack打包后iconfont文件路径的问题
2018/09/01 Javascript
angularJS1 url中携带参数的获取方法
2018/10/09 Javascript
vue 实现左右拖拽元素并且不超过他的父元素的宽度
2018/11/30 Javascript
vue实现购物车抛物线小球动画效果的方法详解
2019/02/13 Javascript
vue-cli+axios实现文件上传下载功能(下载接收后台返回文件流)
2019/05/10 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
2019/08/16 Javascript
js实现内置计时器
2019/12/16 Javascript
[52:09]2014 DOTA2华西杯精英邀请赛 5 25 NewBee VS DK第二场
2014/05/26 DOTA
PyCharm在win10的64位系统安装实例
2017/11/26 Python
python的Tqdm模块的使用
2018/01/10 Python
NLTK 3.2.4 环境搭建教程
2018/09/19 Python
python 实现多维数组转向量
2019/11/30 Python
Python ORM编程基础示例
2020/02/02 Python
python3.6连接mysql数据库及增删改查操作详解
2020/02/10 Python
Numpy 多维数据数组的实现
2020/06/18 Python
scrapy利用selenium爬取豆瓣阅读的全步骤
2020/09/20 Python
Kickers鞋英国官网:男士、女士和儿童鞋
2021/03/08 全球购物
三年大学自我鉴定
2014/01/16 职场文书
前端框架ECharts dataset对数据可视化的高级管理
2022/12/24 Javascript