并发编程中死锁、递归锁、进程/线程池、协程TCP服务器并发等知识点
1、死锁
定义; 类似两个人分别被囚禁在两间房子里,A手上拿着的是B囚禁房间的钥匙,而B拿着A的钥匙,两个人都没法出去,没法给对方开锁,进而造成死锁现象。
具体例子代码如下:
# -*-coding:utf-8 -*-
from threading import Thread,Lock,RLock
import time
muxeA=Lock()
muxeB=Lock() class MyThread(Thread):
def run(self):
self.func1()
self.func2() def func1(self):
muxeA.acquire()
print('%s抢到A锁了'%self.name)
muxeB.acquire()
print('%s抢到B锁了' % self.name)
muxeB.release()
muxeA.release() def func2(self):
muxeB.acquire()
print('%s抢到B锁了' % self.name)
time.sleep(2)
muxeA.acquire()
print('%s抢到A锁了' % self.name)
muxeA.release()
muxeB.release() if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
分析:
当执行func1的时候,第一个人(a)先抢到锁A,这时候,
其他人只能继续等待抢锁A,没有人跟a抢锁B,所以a也抢到锁B,
拿到锁B后,a就把锁B先释放掉,再释放锁A,
继续执行func2,a也顺利抢到锁B,这时候,睡眠2s,
而锁A已经被第二个人抢到了,这时候,第二个人只拿到锁A,没有拿到锁B,
所以没有释放锁A,而a一直在等待抢锁A,没有释放锁B,
所以这时候就造成等待死循环的情况。
执行结果如下:

2、递归锁:
递归锁使用:from reading import RLock
递归锁的特点:
1、可以被连续的acquire和release
2、但是,只能第一个抢到这把锁执行上述操作
3、它内部有一个计数器,每acquire一次计数加一,每realse一次计数减一
4、只要计数不为0,那么其他人都无法抢到该锁
具体例子代码如下:
# -*-coding:utf-8 -*-
from threading import Thread,RLock
import time muxeA=muxeB=RLock() class MyThread(Thread):
def run(self):
self.func1()
self.func2() def func1(self):
muxeA.acquire()
print('%s抢到A锁了'%self.name)
muxeB.acquire()
print('%s抢到B锁了' % self.name)
muxeB.release()
muxeA.release() def func2(self):
muxeB.acquire()
print('%s抢到B锁了' % self.name)
time.sleep(2)
muxeA.acquire()
print('%s抢到A锁了' % self.name)
muxeA.release()
muxeB.release() if __name__ == '__main__':
for i in range(10):
t=MyThread()
t.start()
执行结果如下(没有出现死锁现象):
3、信号量:
定义:就相当于多个互斥锁:
具体例子如下:
from threading import Thread,Semaphore
import time,random
s=Semaphore(5) def task(name):
s.acquire()
print('%s号停车位正在停车'%name)
time.sleep(random.randint(1,5))
s.release() if __name__ == '__main__':
for i in range(10):
t=Thread(target=task,args=(i,))
t.start()
4、事件
比如:一些线程需要等待另一些线程完成才可以操作, 就类似发送信号一样。
from threading import Thread,Event
import time,random
event=Event()
def light():
print("红灯")
time.sleep(3)
print('绿灯')
event.set() #发送信号 def car(name):
print('%s车正在等红灯'%name)
event.wait() #等待对方发信号过来
print('%s车过绿灯'%name) if __name__ == '__main__':
t=Thread(target=light)
t.start()
for i in range(10):
t1=Thread(target=car,args=(i,))
t1.start()
5、线程池、进程池:
池的概念:就是保证计算硬件的安全前提下,最大限度的利用计算机。
它降低运行效率,但是,保证了计算机硬件的安全。
注意: 池里面原有的线程或进程是不会重复出现创建和销毁的过程。
#线程池的创建:
pool=ThreadPoolExecutor()
#括号内为线程池中进程的个数,你可以自己设置,默认是5个,最大不会超过32个
ThreadPoolExecutor类中的参数max_workers就是池中线程数:初始设置代码如下:
max_workers = min(32, (os.cpu_count() or 1) + 4) #进程池的创建:
pool=ProcessPoolExecutor()
#它的参数如下:os.cpu_count()表示电脑的CPU核数
self._max_workers = os.cpu_count() or 1 总结:关键代码如下:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
pool=ProcessPoolExecutor()
pool=ThreadPoolExecutor(5)
res=pool.submit(task,i).add_done_callback(call_back)
进程/线程池的例子如下:
# -*-coding:utf-8 -*-
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os # pool=ThreadPoolExecutor(5)
pool=ProcessPoolExecutor() def call_back(n):
print(">>:",n.result())
def task(n):
print(n,os.getpid())
time.sleep(2)
return n*n if __name__ == '__main__':
# list_pool=[]
for i in range(10):
res=pool.submit(task,i).add_done_callback(call_back)
6、协程、gevent模块:
实质:就是一个思想,它是由程序员自己在代码层面上检测IO操作,一旦遇到IO操作就会在代码级别上完成切换
注意:IO操作下的切换才是提高效率的,非IO操作下的切换会降低效率。
gevent模块的使用需要打猴子补丁,不然不会检测到像time.sIeep()等O操作
#猴子补丁
from gevent import monkey
monkey.patch_all()
具体例子如下:
# -*-coding:utf-8 -*-
#猴子补丁
from gevent import monkey
monkey.patch_all() from gevent import spawn
import time def ha():
print('hahaha')
time.sleep(2)
print('hahaha') def xixi():
print('xixi')
time.sleep(3)
print('xixi') if __name__ == '__main__':
start_time=time.time()
g1=spawn(ha)
g2=spawn(xixi)
g1.join()
g2.join()
print(time.time()-start_time)
7、基于协程的TCP并发:
服务端例子如下:
# -*-coding:utf-8 -*-
#猴子补丁
from gevent import monkey;monkey.patch_all() from gevent import spawn
import socket def new_server(ip,addr):
server=socket.socket()
server.bind((ip,addr))
server.listen(5)
while True:
conn,addr=server.accept()
spawn(connect,conn) def connect(conn):
while True:
try:
data=conn.recv(1024)
print(data.decode())
if len(data)==0:break
conn.send(data.upper())
except Exception as e:
print(e)
break
if __name__ == '__main__':
g1=spawn(new_server,'localhost',8080)
g1.join()
客户端代码如下:
# -*-coding:utf-8 -*-
import socket
from threading import Thread,current_thread def new_client():
c=socket.socket()
c.connect(('localhost',8080))
while True:
data=('你好,我是%s'%current_thread().name)
c.send(data.encode())
data1=c.recv(1024)
print(data) if __name__ == '__main__':
for i in range(200):
t=Thread(target=new_client)
t.start()
并发编程中死锁、递归锁、进程/线程池、协程TCP服务器并发等知识点的更多相关文章
- Java 并发编程中的 Executor 框架与线程池
Java 5 开始引入 Conccurent 软件包,提供完备的并发能力,对线程池有了更好的支持.其中,Executor 框架是最值得称道的. Executor框架是指java 5中引入的一系列并发库 ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
- Java并发编程:Java的四种线程池的使用,以及自定义线程工厂
目录 引言 四种线程池 newCachedThreadPool:可缓存的线程池 newFixedThreadPool:定长线程池 newSingleThreadExecutor:单线程线程池 newS ...
- python进程.线程和协程的总结
I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...
- python并发编程之多进程、多线程、异步、协程、通信队列Queue和池Pool的实现和应用
什么是多任务? 简单地说,就是操作系统可以同时运行多个任务.实现多任务有多种方式,线程.进程.协程. 并行和并发的区别? 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任 ...
- python-GIL、死锁递归锁及线程补充
一.GIL介绍 GIL全称 Global Interpreter Lock ,中文解释为全局解释器锁.它并不是Python的特性,而是在实现python的主流Cpython解释器时所引入的一个概念,G ...
- python并发编程-进程池线程池-协程-I/O模型-04
目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...
- 【java并发编程实战】第八章:线程池的使用
1.线程饥饿锁 定义:在线程池中,如果任务的执行依赖其他任务,那么可能会产生线程饥饿锁.尤其是单线程线程池. 示例: public class ThreadDeadStarveTest { publi ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
随机推荐
- Web框架的原理详情
Web框架的原理 Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. socket服务 ...
- Linked server的一个问题
好久没有写新的博客,主要是很久没有什么动力和需求来写程序.虽然也不是一点没写,但都缺乏技术含量,没什么可说的. 前两天碰到一个关于linked server的问题.本地的sql server里,通过l ...
- 跟我一起学.NetCore之配置变更监听
前言 通常程序中配置少不了,配置的修改也避免不了,配置的热更新为此给应用程序带来很大的便捷,不用重启,提高用户体验:但往往有时候需要对修改进行审计,也就是需要记录,有时候也会针对配置修改的时候触发相关 ...
- MySQL最全存储引擎、索引使用及SQL优化的实践
1 MySQL的体系结构概述 整个MySQL Server由以下组成 :Connection Pool :连接池组件Management Services & Utilities :管理服务和 ...
- SpringCloud Alibaba之Nacos
一.运行Nacos Nacos GitHub开源地址:https://github.com/alibaba/nacos Nacos 官方文档:https://nacos.io/zh-cn/docs/q ...
- lammps计算的应力的方法
摘自:http://dxli75.blog.163.com/blog/static/106768289201142893419587/ lammps计算的应力有两种: 一是体系整体的应力状态,通过在t ...
- Windows Server 2012 数据库定时备份
为了数据的安全,我们在服务器上设置了每周备份一次,下面是具体步骤: 一.在文件客户端服务器创建db_backup.cmd的Windows命令脚本.输入以下内容(直接复制可能出错,请手动输入): @ec ...
- [CSP-S2019]树的重心 题解
CSP-S2 2019 D2T3 考场上扔了T2来打这题的部分分,然后没看到数据范围是等号,不知道怎么判完全二叉树然后40分滚粗…… ---- 思路分析 很容易想到$O(n^2)$每次暴力找重心,这个 ...
- C# 接口的Get、Post、WebService请求方法一览,值得收藏
C# 接口的Get.Post.WebService请求方法一览,值得收藏 public static class HttpHelper { const string DEFAULT_USER_AGEN ...
- 让“不确定性”变得有“弹性”?基于弹性容器的AI评测实践
0. 前言 AI的场景丰富多彩,AI的评价方法百花齐放,这对于设计一套更通用的评测框架来说,是一个极大的挑战,需要兼顾不同的协议,不同的模型环境,甚至是不同的操作系统.本文分享了我们在AI评测路上的一 ...