python锁机制_python基础(锁机制,守护线程,线程队列,线程池)

一、 互斥锁(Lock)与递归锁(RLock)机制

1.1 由互斥锁(Lock)产生的死锁现象:

#互斥锁(死锁现象):

#死锁现象:

from threading importLock

lock=Lock()

lock.acquire()print(123)

lock.acquire()#等待获取锁(死锁状态)

print(456)

lock.release()#等待释放锁

lock.release()print('程序结束!!!')#科学家吃面产生的死锁现象:

from threading importLock, Threadimporttime

noodle_lock= Lock() #面条锁

fork_lock = Lock() #叉子锁

defeat1(name):

noodle_lock.acquire()

time.sleep(0.5)print('%s拿到面了' %name)

fork_lock.acquire()print('%s拿到叉子了' %name)print('%s吃面' %name)

fork_lock.release()print('%s放下叉子了' %name)

noodle_lock.release()print('%s放下面了' %name)defeat2(name):

fork_lock.acquire()print('%s拿到叉子了' %name)

noodle_lock.acquire()print('%s拿到面了' %name)print('%s吃面' %name)

noodle_lock.release()print('%s放下面了' %name)

fork_lock.release()print('%s放下叉子了' %name)#三个线程(科学家)需同时获取叉子和面条才能吃到面条

Thread(target=eat1, args=('Annie',)).start()

Thread(target=eat2, args=('Lisa',)).start()

Thread(target=eat1, args=('Jane',)).start()

View Code

1.2 解决由互斥锁产生的死锁,可重入锁(递归锁:RLock)解决方法:

#递归锁(可重入锁):

#方式一:#RLock:解决死锁问题(建议少用递归锁,一般程序的递归锁的出现都是程序设计不合理导致):

from threading importRLock, Threadimporttime

fork_lock= noodle_lock =RLock()defeat1(name):

noodle_lock.acquire()#获取递归锁(进入第一层)

print('%s拿到面了' %name)

time.sleep(0.5)

fork_lock.acquire()#获取递归锁(进入第二层)

print('%s拿到叉子了' %name)print('%s吃面' %name)

fork_lock.release()#释放递归锁(出第二层)

print('%s放下叉子了' %name)

noodle_lock.release()#释放递归锁(出第一层)

print('%s放下面了' %name)defeat2(name):

fork_lock.acquire()print('%s拿到叉子了' %name)

noodle_lock.acquire()print('%s拿到面了' %name)print('%s吃面' %name)

noodle_lock.release()print('%s放下面了' %name)

fork_lock.release()print('%s放下叉子了' %name)

Thread(target=eat1, args=('Annie',)).start() #线程一

Thread(target=eat2, args=('Lisa',)).start() #线程二

Thread(target=eat1, args=('Jane',)).start() #线程三

#方式二:#直接使用互斥锁结果科学家吃面问题:

from threading importLock, Thread

lock=Lock()defeat1(name):

lock.acquire()#获取锁

print('%s拿到面了' %name)print('%s拿到叉子了' %name)print('%s吃面' %name)print('%s放下叉子了' %name)print('%s放下面了' %name)

lock.release()#释放锁

defeat2(name):

lock.acquire()print('%s拿到叉子了' %name)print('%s拿到面了' %name)print('%s吃面' %name)print('%s放下面了' %name)print('%s放下叉子了' %name)

lock.release()

Thread(target=eat1, args=('Annie',)).start() #线程一

Thread(target=eat2, args=('Lisa',)).start() #线程二

Thread(target=eat1, args=('Jane',)).start() #线程三

View Code

1.3 总结:

gil锁机制:保证线程同一时刻只能一个线程访问CPU,不可能有两个线程同时在CPU上执行指令

lock锁机制:保证某一段代码 在没有执行完毕之后,不可能有另一个线程也执行这一段代码

二、 线程锁实现

为什么要使用线程锁:

1. 同一时刻同一段代码,只能有一个进程来执行这段代码

2. 锁的应用场景,当多个进程需要操作同一个文件/数据库的时候 ,

3. 会产生数据不安全,我们应该使用锁来避免多个进程同时修改一个文件

示例:

#示例:

importjsonimporttimefrom multiprocessing importProcess, Lock#查询余票

defsearch_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)print('%s查询余票为%s' % (name, dic['count']))#购买车票

defbuy_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)

time.sleep(2)if dic['count'] >= 1:print('%s买到票了' %name)

dic['count'] -= 1time.sleep(2)

with open('ticket', mode='w', encoding='utf-8') as f:

json.dump(dic, f)else:print('余票为0,%s没买到票' %name)#使用线程锁方式一:

defuse1(name, lock):

search_ticket(name)print('%s在等待' %name)

lock.acquire()#获取锁

print('%s开始执行了' %name)

buy_ticket(name)

lock.release()#释放锁

#使用线程锁方式二:

defuse2(name, lock):"""# with lock:

# 代码块

# 上下文管理:在__enter__方法中获取锁(acquire),在__exit__方法中释放锁(release)"""search_ticket(name)print('%s在等待' %name)

with lock:#获取锁 + 释放锁

print('%s开始执行了' %name)

buy_ticket(name)if __name__ == '__main__':

lock=Lock()

l= ['alex', 'wusir', 'baoyuan', 'taibai']for name inl:

Process(target=use1, args=(name, lock)).start() #方式一

Process(target=use2, args=(name, lock)).start() #方式二

View Code

三、 队列(Queue,LifoQueue,PriorityQueue)的使用

3.1 先进先出队列(Queue):

#先进先出队列#Queue就是一个线程队列的类,自带lock锁,实现了线程安全的数据类型

from queue importQueue

q=Queue()

q.put({1, 2, 3})

q.put_nowait('abc')print(q.get_nowait()) #获取一个值,如果没有抛出异常

print(q.get())

q.empty()#判断是否为空

q.full() #判断是否为满

q.qsize() #查看队列的大小

View Code

3.2 先进后出队列(栈:LifoQueue):

#先进后出的队列(last in first out):#线程安全的队列 栈和后进先出的场景都可以用

from queue importLifoQueue

lfq=LifoQueue()

lfq.put(1)

lfq.put('abc')

lfq.put({'1', '2'})print(lfq.get()) #{'2', '1'}

print(lfq.get()) #abc

print(lfq.get()) #1

View Code

3.3 优先级队列(PriorityQueue):

#优先级队列:

from queue importPriorityQueue

pq=PriorityQueue()

pq.put((10, 'aaa'))

pq.put((2, 'bbb'))

pq.put((20, 'ccc'))print(pq.get()) #最想获取到优先级最高的2,以元组形式返回 (2, 'bbb')

print(pq.get()) #(10, 'aaa')

print(pq.get()) #(20, 'ccc')

View Code

四、线程队列(生产者与消费者模型)

#生产者与消费者示例:

importtimeimportrandomfrom queue importQueuefrom threading importThread#生产者

defproducer(q):for i in range(10):

time.sleep(random.random())

food= 'Spam %s' %iprint('%s生产了%s' % ('Jane', food))

q.put(food)#消费者

defconsumer(q, name):whileTrue:

food= q.get() #food = 食物/None

if not food: break #当消费者消费完成后,最后拿到None时,退出消费者程序

time.sleep(random.uniform(1, 2))print('%s 吃了 %s' %(name, food))if __name__ == '__main__':

q=Queue()

p1= Thread(target=producer, args=(q,)) #生产者

p1.start()

c1= Thread(target=consumer, args=(q, 'Lisa')) #消费者

c1.start()

c2= Thread(target=consumer, args=(q, 'Annie')) #消费者

c2.start()

p1.join()

q.put(None)#生产者完成生产后,队列最后加入None,表示已经生产完成

q.put(None) #每个消费者需要None退出程序

View Code

五、守护线程:

5.1 守护线程的定义:

1. 主线程会等待子线程的结束而结束

2. 守护线程会守护主线程和所有的子线程

3. 守护线程会随着主线程的结束而结束,主线程结束,进程资源回收,守护线程被销毁

示例:

#守护线程示例:

importtimefrom threading importThread#守护线程

defdaemon_func():whileTrue:

time.sleep(0.5)print('守护线程')#其他子线程

defson_func():print('start son')

time.sleep(5)print('end son')

t= Thread(target=daemon_func) #开启守护线程

t.daemon =True

t.start()

Thread(target=son_func).start() #开启son_func子线程

time.sleep(3)print('主线程结束') #主线程代码结束后,等待子线程son_func结束

View Code

总结:

守护进程 :只会守护到主进程的代码结束

守护线程 :会守护所有其他非守护线程的结束

六、线程池

线程池模块与进程池共用同一个模块:concureent.futures

示例:

#线程池:

from urllib.request importurlopenfrom concurrent.futures import ThreadPoolExecutor #导入线程池类

#获取网页

defget_html(name, addr):

ret=urlopen(addr)return {'name': name, 'content': ret.read()}#保存数据

defcache_page(ret_obj):

dic=ret_obj.result()

with open(dic['name'] + '.html', 'wb') as f:

f.write(dic['content'])

url_dic={'协程': 'http://www.cnblogs.com/Eva-J/articles/8324673.html','线程': 'http://www.cnblogs.com/Eva-J/articles/8306047.html','目录': 'https://www.cnblogs.com/Eva-J/p/7277026.html','百度': 'http://www.baidu.com','sogou': 'http://www.sogou.com'}#创建20个线程#方式一:

t = ThreadPoolExecutor(20) #实例化线程池对象

for url inurl_dic:

task= t.submit(get_html, url, url_dic[url]) #提交线程任务

task.add_done_callback(cache_page) #函数回调,数据保存

#方式二:

with ThreadPoolExecutor(20) as t: #上下文管理方式实现实例化的线程池

for url inurl_dic:

task=t.submit(get_html, url, url_dic[url])

task.add_done_callback(cache_page)

View Code

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java包图标是文件_关于更换.jar文件默认图标

最近写了个java程序,导出.jar文件后觉得默认图标太寒酸,想换一个自个儿喜欢的。eclipse导出.jar文件网上提供了很多很正确的方法,我也不必赘述。至于更改默认图标,网上提供的一些方法真是让人不敢恭维。部分人提供的方法是“右击-…

qlineedit限制输入数字_Excel单元格限制录入,实用小技巧

在填写资料表格的时候,为了不防止出错,会在单元格中设置一些技巧,限制对方输入内容,这样可以更好的预防输入错误。那么单元格限制输入技巧是如何实现的呢?1、限制只能录入数字比如单元格是我们要用来填写年龄数据等数字…

java二维数组 内存分配_java中二维数组内存分配

区分三种初始化方式:格式一:数据类型[][] 数组名 new 数据类型[m][n];m:表示这个二维数组有多少个一维数组。n:表示每一个一维数组的元素有多少个。//例:int arr[][]new int[3][2];如下图格式二:数据类型[][] 数组名 new 数据类…

如何在python官网下载pip_[Python]Pip的安装以及简单的使用

Pip的安装安装python以后(我的python版本是32位,版本号2.7.10),如果需要安装一些其他的库,一般有两种办法,一种是自己手动去各个库的官网下载,自己安装;另一种方法是安装pip,使用pip可以方便安装…

java造型_java造型_java向上造型有什么作用为什么要造型有什么效果_彩妆阁

1、java中造型与转型都什么意思,怎么用?我知道我知道 造型就是款式比如新款 爆款 秒杀款卖爆了等等这就是造型至于转型比如你之前写Java然后写.net 就叫转型了啦2、java中上溯造型是什么原理Upcasting,上溯造型,有的书译作“向上转…

word公式插件_如何快速输入复杂的数学公式?这里有 3 个实用技巧

不管你是不是科研狗,都可能遇到过在文章中插入公式。而我们最常用的就是使用 Word 自带的公式编辑器输入,Word 公式可以很好地匹配文章的格式,自然地插入文中。有时候处理一个公式简单,但如果你要输入大量公式,键盘、鼠…

java动作监听退出程序_监听获取程序退出事件(Linux、Windows、Java、C++)

监听程序退出事件,主要是用于程序的优雅退出。下面针对Java、C在Windows、Linux下的处理分别进行介绍.1.Java监听程序退出事件Java本身是跨平台的,不必关系Windows还是Linux。具体做法如下:通过Runtime.getRuntime().addShutdownHook(Thread …

python创建access表_Access创建表

有了数据库管理系统,在输入数据之前,您需要创建表。 Microsoft Access创建表非常容易。 事实上,当你创建一个数据库,Access创建你的第一个表(称为Table1)。通常情况下,当你需要创建一个新的表,选择CREATE &…

java观察者模式本质_6.[研磨设计模式笔记]观察者模式

1.定义定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。2.解决问题——订阅报纸看起来订阅者是直接根有据打交道,但实际上,订阅者的订阅数据是被邮寄传递到报社&#xff0…

python r语言 作图_生物医学绘图,Python 并不比R语言差

做过基因测序和生物信息学分析,尤其是做过RNAseq分析的同学都知道,R语言中有一款数据可视化神器ggplot2,其绘图功能强大,但它的缺陷是不能直接绘制3D图形,需要加载扩展包,很麻烦。如果用Python语言&#xf…

粒子群算法tsp java_粒子群算法解决TSP问题

1. 粒子群算法简介粒子群算法(particle swarm optimization,PSO)由Kennedy和Eberhart在1995年提出,属于进化算法的一种,是通过对模拟鸟群扑食行为设计的。基本思想:从随机解出发,通过迭代寻找最优解,通过适…

python 3.5.2页面_Python 3.5.2实现websocket服务端

最近由于一个项目需要,写了一个简易的websocket服务端程序,其间也参考了网上的很多资料,我将用接下来的几个篇幅说明是怎么实现的,及遇到的一系列埂。参考 (包括且不限于如下地址)涉及到的模块socket:socket通讯如侦听…

java连接sqlserver 的sqlhelper类_SQLserver数据库操作帮助类SqlHelper

using System;using System.Data;using System.Xml;using System.Data.SqlClient;using System.Collections;namespace SQL.Access{/// /// SqlServer数据访问帮助类/// public sealed class SqlHelper{#region 私有构造函数和方法private SqlHelper() {}/// /// 将SqlParamete…

python编写抢座位软件_程序员硬核Python抢票教程”,帮你抢回家车票

盼望着,盼望着,春节的脚步近了,然而,每年到这个时候,最难的,莫过于一张回家的火车票。据悉,今年春运期间,全国铁路发送旅客人次同比将增长8.0%,达到4.4亿人次&#xff0c…

java io 缓存读取_Java 文件IO写入读取四种方法

第一种:字节流 FileInputStream FileOutputStream1.1 读取操作//先创建一个和硬盘连接的流(打通硬盘和内存的通道)FileInputStream fis new FileInputStream("D:\\Demo.txt");//创建缓存区大小是1kbyte[] bytes new byte[1024];int data 0; //存储有效…

python集合可以修改吗_修改包含Python3中的集合的集合列表-问答-阿里云开发者社区-阿里云...

我试图创建一个以元组为元素的列表。每个元组都有4个整数。前两个整数是对2个range进行压缩的结果,而其他2个则是对2个不同的整数进行压缩的结果。我正在使用此代码创建元组和最终列表,这些列表是从笛卡尔乘积派生的,如下所示:获取…

hive mysql性能_Hive数据库安全审计功能

【Hive数据库安全审计简介】Hive数据库安全审计是一款基于数据库通讯协议准确分析和SQL完全解析技术的数据库安全审计系统。实现了对数据库操作、访问用户及外部应用用户的审计,可以用于安全合规、用户行为分析、运维监控、风控审计、事件追溯等与数据库安全相关的管…

linux安装sz rz_超级好用的文件传输命令rz与sz

做生物信息经常需要在本地客户端与服务器之间进行文件的传输,例如将要分析的数据传到Linux服务器上,进行分析,分析结束之后将结果下载到本地windows系统进行查看。以前我们都推荐大家使用比较稳定,并且支持断点续传的Filezilla或者…

java mongodb gridfs_查询MongoDB GridFS元数据(Java)

我想要做的是通过查询元数据的字段来获取GridFS文件列表.例如,我得到一个GridFS文件文件,如下所示:{ "_id" : { "$oid" : "4f95475f5ef4fb269dbac954"} , "chunkSize" : 262144 , "length" : 3077 , "md5&q…

php 防止跨站脚本攻击,php防止sql注入以及xss跨站脚本攻击

1.post数据封装转义函数 防sql注入 eag:addslashes($username);​addslashes($password);​eag:防止sql注入函数封装function deepslashes($data){#判断$data的表现形式 并且需要处理空的情况if(empty($data)){return($data);}​#高级简写 return is_array($data) …