并发编程中死锁、递归锁、进程/线程池、协程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方法.这篇文章是接着上一篇文章 ...
随机推荐
- Mybatis-09-缓存
缓存 什么是缓存[Cache]? 存在内存中的临时数据 提高查询效率,解决高并发的性能问题 为什么使用缓存? 减少和数据库的交互次数,减少系统开销,提高系统效率 什么样的数据能使用缓存? 经常查询且不 ...
- js使用html2canvas 生成图片然后下载
1:html2canvas官网 首先去官网把这个JS下载下来 <!DOCTYPE html> <html lang="en"> <head> & ...
- IDEA - 错误提示 Could not autowire. No beans of '' type found
工具: IntelliJ IDEA 2019.3.4 x64 Ultimate,maven项目: 现象:如下图所示,出现Could not autowire. No beans of '' type ...
- 解决QT5移植报错:This application failed to start because no Qt platform plugin could be initialized
今天自己基于Pyqt5开发了一个软件,打包成exe后在自己的电脑上运行正常,在其他机器上提示: This application failed to start because no Qt platf ...
- idea git拉取、合并、处理冲突、提交代码具体操作
早在两个月前我还在用eclipse开发,并且也发布的一些eclipse git的相关操作(操作都是本人亲自实践过的),但由于项目团队要求,开发工具统一用idea,实在不得已而为之切换了开发工具, 初次 ...
- Kubernetes 中 Informer 的使用
原文链接:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247485580&idx=1&sn=7392dbadf ...
- 使用Seq搭建免费的日志服务
Seq简介 Seq是老外开发的一个针对.NET平台非常友好的日志服务.支持容器部署,提供一个单用户免费的开发版本. 官网:https://datalust.co/seq 使用文档:https://do ...
- v-html渲染富文本图片宽高问题
v-html渲染富文本v-html是用来渲染html的节点及字符串的,但是渲染后富文本里的图片宽高会溢出所在div的区域但是使用css直接给img是没有办法设置img的宽高的,需要使用深层级来给img ...
- 为什么网站URL需要设置为静态化
http://www.wocaoseo.com/thread-95-1-1.html 为什么网站URL需要静态化?网站url静态化的好处是什么?现在很多网站的链接都是静态规的链接,但是网站 ...
- WPF 使用WindowChrome自定义窗体 保留原生窗体特性
本文大幅度借鉴dino.c大佬的文章 https://www.cnblogs.com/dino623/p/uielements_of_window.html https://www.cnblogs.c ...