并发编程中死锁、递归锁、进程/线程池、协程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方法.这篇文章是接着上一篇文章 ...
随机推荐
- 记录使用Python登录浙江大学统一身份认证
背景 现在每天要进行健康情况上报,但是因为经常睡过头忘记打卡,于是想着写一个程序来自动打卡. 统一身份认证 访问健康情况上报页面(https://healthreport.zju.edu.cn/nco ...
- web基础(四)严格模式与混杂模式
web基础(四)严格模式与混杂模式 一.介绍 DOCTYPE 标签是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样的文档类型定义(DTD)来解析文档.DO ...
- Android Studio gridview 控件使用自定义Adapter, 九宫格items自适应全屏显示
先看效果图,类似于支付宝首页的效果.由于九宫格显示的帖子网上已经很多,但是像这样九宫格全屏显示的例子还不是太多.本实例的需求是九宫格全屏显示,每个子view的高度是根据全屏高度三等分之后自适应高度,每 ...
- Chevereto免费图床搭建教程 | vps搭建免费图床教程
Chevereto免费图床搭建教程 | vps搭建免费图床教程 本文首发于:https://chens.life/How-to-build-a-free-image-bed.html 前言 自从有了个 ...
- Arraylist的源码学习
@ 目录 ArrayList简介 ArrayList核心源码 ArrayList源码分析 System.arraycopy()和Arrays.copyOf()方法 两者联系与区别 ArrayList ...
- Navicat15破解+网盘位置
百度网盘Navicat.15位置 链接:https://pan.baidu.com/s/1Vn0Qnt8IUA37a-p4hAnk5g 提取码:clq3 1.百度网盘下载完后,点这个安装Navicat ...
- java应用中的日志介绍
日志在应用程序中是非常非常重要的,好的日志信息能有助于我们在程序出现 BUG 时能快速进行定位,并能找出其中的原因. 但是,很多介绍 AOP 的地方都采用日志来作为介绍,实际上日志要采用切面的话是极其 ...
- Jmeter系列(51)- 详解 Transaction Controller 事务控制器
如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 简单介绍 可以添加多个取样器(samp ...
- js 常用业务工具方法 (es5,es6)持续更新
数组去重 数组去重最原始的方法就是使用双层循环. es5: // 使用indexOf function unique(array) { var res = []; for (var i = 0, le ...
- Adaptive Critics and the Basal Ganglia
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! This Article is brought to you for free and open access by the Comput ...