一、死锁与递归锁(了解)

1 死锁

程序中如果出现多个锁操作容易造成死锁现象

from threading import Thread,Lock

import time
# 实例化两个锁对象
a = Lock()
b = Lock() class MyThread(Thread):
def run(self):
self.func1()
self.func2() def func1(self):
a.acquire() # 10个线程去抢和这个锁
print(self.name)
b.acquire() # 抢到a的才能抢b
print(self.name)
b.release()
a.release() # 施放a的时候 线程2瞬间抢到了a开始执行 def func2(self):
b.acquire() # 线程1抢到b和线程2互相卡死,因为需要对方的锁才能施放自己的锁
print(self.name)
time.sleep(2)
a.acquire()
print(self.name)
a.release()
b.release() for i in range(10):
t = MyThread()
t.start()

2 递归锁

"""
递归锁的特点
可以被连续的acquire和release
但是只能被第一个抢到这把锁执行上述操作
它的内部有一个计数器 每acquire一次计数加一 每realse一次计数减一
只要计数不为0 那么其他人都无法抢到该锁
"""
# 将上述的
mutexA = Lock()
mutexB = Lock()
# 换成
mutexA = mutexB = RLock()

二、信息量

信号量在不同的阶段可能对应不同的技术点

在并发编程中信号量指的是锁

from threading import Thread, Semaphore
import time
import random sm = Semaphore(5) # 括号内写数字 写几就表示开设几个坑位
# 内置方法和锁一样,抢和施放
# 区别在于信号量可以规定一次性抢锁的最大数量 def task(name):
sm.acquire()
print('%s 正在蹲坑'% name)
time.sleep(random.randint(1, 5))
sm.release() if __name__ == '__main__':
for i in range(20):
t = Thread(target=task, args=('伞兵%s号'%i, ))
t.start()

三、Event事件

一些进程或者线程遇到等待另外一些进程或者线程运行完毕之后才能运行,类似发射信号

from threading import Thread, Event
import time 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(20):
t = Thread(target=car, args=('%s'%i, ))
t.start()

四、三种优先级数据操作

同一个进程下多个线程数据共享,但为了保证数据安全,我们需要用到以下三种数据操作

1 队列

原则:先进先出

import queue

q = queue.Queue(3)

q.put(1)
q.put(2)
q.put(3) print(q.empty()) # 判断队列是否为空
print(q.full()) # 判断队列是否为满 q.get()
q.get()
q.get()
q.get(timeout=3) # 等待3秒再取数据,如果没有就报错
q.get_nowait() # 不等待,没有数据就报错

2 堆栈

原则:先进后出

堆栈
import queue q = queue.LifoQueue(3) # last in first out q.put(1)
q.put(2)
q.put(3) print(q.get())
>>> 3

3 自定义优先级

import queue

q = queue.PriorityQueue(3) # 上传数据时要先上传一个该数字排名,排名小的现出来

q.put(('5',1))
q.put(('0',1))
q.put(('-1',1)) print(q.get_nowait())
>>> ('-1',1)

五、进程池和线程池

之前在tcp实现并发的时候我们是来一个用户就启用一个线程或者进程去为用户服务
但是计算机的硬件资源目前还无法支持我们无限制的开发线程
所以用到了池的概念
池相当于缓冲地带,让我们可以保证计算机在正常运行的情况下最大限度的利用它
它降低了程序的运行效率,但是保证了计算机的安全 如果把计算机比喻成一个小池子你限定了池子最大容量是1,你要喂食,池子就会先产生一条鱼,给你喂,其他人想喂就得等你结束,过来喂的是同一条鱼 而如果不用池的概念去限定,每个人来池子都会给人产生一条鱼来服务,鱼多了,池子就炸了。

基本使用

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
import os # pool = ThreadPoolExecutor(5)# 线程池里只有5个线程
pool = ProcessPoolExecutor(2)# 进程池里只有5个进程
# 括号内可以传数字 不传的话默认会开设当前计算机cpu个数五倍的线程
# 池子造出来之后 里面会固定存在五个线程
# 这个五个线程不会出现重复创建和销毁的过程
# 池子的使用非常的简单
# 你只需要将需要做的任务往池子中提交即可 自动会有人来服务你 def text(n):
print(os.getpid())
time.sleep(3)
return n**n def callback(n):
print(n.result()) if __name__ == '__main__':
res = pool.submit(text,2) # 返回值是一个对象 # print('主') # 异步提交,判断异步的方式,在任务提交后得到返回值之前能不能执行代码 # print(res.result()) # 得到的是提交任务的返回值 t_list = []
for i in range(10):
pool.submit(text,i).add_done_callback(callback) # 自定义异步回调机制,在任务得到返回值的时候直接调用里面的函数
# 这种回调机制可以想象为,在提交任务后,直接运行下面的代码,什么时候有返回值了,会立刻调用该方法,相当于埋下了定时炸弹,返回值来了就触发
# res = pool.submit(text,i).result() # 这种得到结果的方式是同步
# t_list.append(res)
# pool.shutdown() # 关闭所有线程
# for i in t_list:
# print(i)

六、协程

  • 进程:资源单位
  • 线程:执行单位
  • 协程:意淫出来的
    • 为了在多线程实现并发,我们在多线程中出现io情况都切换走,去执行其他线程,这样就会让计算机看起来一直在运行没有中断过。从而提升了程序的运行效率

七、gevent模块

from gevent import monkey;monkey.patch_all()
# 猴子补丁,用来检测程序里出现的io操作
import time
from gevent import spawn def a():
print('a')
time.sleep(2)
print('a end') def b():
print('b')
time.sleep(4)
print('b end') start = time.time()
g1 = spawn(a)
g2 = spawn(b)
g1.join()
g2.join()# 等待任务执行完再执行后面的代码
print(time.time()-start) # 4.015194654464722 实现了io时间切换操作,用户只需等待最长的任务时间

八、协程实现tcp并发

#服务端
import socket
from gevent import monkey;monkey.patch_all()
from gevent import spawn def communication(conn):
while True:
try:
msg = conn.recv(1024)
if len(msg) == 0:break
conn.send(msg.upper())
except Exception as e:
print(e)
break
conn.close() def sever(ip,port):
s = socket.socket()
s.bind((ip, port))
s.listen(5)
while True:
conn,addr = s.accept()
communication(conn) if __name__ == '__main__':
g = spawn(sever,'127.0.0.1',8080)
g.join() # 客户端 import socket
from threading import Thread,current_thread def client():
s = socket.socket()
s.connect(('127.0.0.1', 8080))
n = 0
while True:
msg = '%s say hello %s' % (current_thread().name, n)
n += 1
s.send(msg.encode('utf-8'))
data = s.recv(1024)
print(data.decode('utf-8')) if __name__ == '__main__':
for i in range(50):
t = Thread(target=client)
t.start()

最新文章

  1. 0525 SCRUM项目7.0
  2. HTML—one
  3. hiho 光棍节
  4. 实体框架 (EF) 入门 => 六、性能注意事项
  5. LeetCode 337
  6. OpenSSL与公钥私钥证书签名的千丝万缕
  7. ClassLoader 工作机制
  8. vim如何显示行号
  9. Web Api 接收图片
  10. 框架学习之Struts2(三)---OGNL和值栈
  11. Python中模块之os的功能介绍
  12. css 四周边框角加粗效果
  13. ASP.Net Core开发(踩坑)指南
  14. VUE的一个数据绑定与页面刷新相关的bug
  15. java8 lambda方法引用
  16. 微信小程序—文件系统
  17. Navicat导入sql server数据库
  18. IOS 应用发布流程
  19. Zabbix-2.X/3.X监控工具监控Redis以及zabbix Redis监控模板下载
  20. JAVA基本类型和包装类

热门文章

  1. v-else-if(v-show)
  2. [apue] sysconf 的四种返回状态
  3. PuTTY通过SSH连接上Ubuntu20.04
  4. TensorFlow从0到1之矩阵基本操作及其实现(7)
  5. Python绘图之Turtle库详解(1)
  6. MySQL 性能优化细节
  7. Java8新特性之函数式接口
  8. 深入理解Java虚拟机学习笔记(一)-----Java内存区域
  9. Docker中使用RabbitMQ
  10. RabbitMQ入门,我是动了心的