并发编程中死锁、递归锁、进程/线程池、协程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方法.这篇文章是接着上一篇文章 ...
随机推荐
- Maven项目在进行单元测试报错:ClassNoFoundExceptipon
解决方法: 只要把Java--------compiler-------building-------Buil path problems ------- incomplete build path ...
- clients-producer-组包发送消息
- 浏览器自动化的一些体会9 访问angular页面的一个问题
发现浏览器自动化有一个重要方面没有提及,即所谓的无页面浏览器,不过最近没有需求,不想尝试,先记上一笔,以后有需求时,可以有个思路. 大约一两个月前(现在比较懒散,时间不知不觉过去,连今天是几号有时候都 ...
- ganglia访问时出现"You don't have permission to access /ganglia/ on this server"
安装ganglia后,访问浏览器出现"You don't have permission to access /ganglia/ on this server" 按照网络上的要求配 ...
- MySQL标识列(自增长列)
#标识列/*又称为自增长列含义:可以不用手动的插入值,系统提供默认的序列值 特点:1.标识列必须和主键搭配吗?不一定,但要求是一个key2.一个表可以有几个标识列?至多一个!3.标识列的类型只能是数值 ...
- Host 'controller' is not mapped to any cell
问题: Host 'controller' is not mapped to any cell 解决: 执行:nova-manage cell_v2 simple_cell_setup 再次检查:
- MySQL数据库中查询数据库表、字段总数量,查询数据总量
最近要查询一些数据库的基本情况,由于以前用oracle数据库比较多,现在换了MySQL数据库,就整理了一部分语句记录下来. 1.查询数据库表数量 #查询MySQL服务中数据库表数据量 SELECT C ...
- springboot整合druid监控配置
方式一:直接引入druid 1.maven坐标 <dependency> <groupId>com.alibaba</groupId> <artifactId ...
- JAVA作业—字符串操作
------------恢复内容开始------------ ------------恢复内容开始------------ ------------恢复内容开始------------ ------- ...
- A Review on Generative Adversarial Networks: Algorithms, Theory, and Applications
1 Introduction GANs由两个模型组成:生成器和鉴别器.生成器试图捕获真实示例的分布,以便生成新的数据样本.鉴别器通常是一个二值分类器,尽可能准确地将生成样本与真实样本区分开来.GANs ...