day42 Pyhton 并发编程05
一.内容回顾
# 线程
# 正常的编程界:
# 进程
# 计算机中最小的资源分配单位
# 数据隔离
# 进程可以独立存在
# 创建与销毁 还有切换 都慢 给操作系统压力大
# 线程
# 计算机中能被CPU调度的最小单位
# 同一个进程中的多个线程资源共享
# 线程必须依赖进程存在
# 创建与销毁 还有切换 都比进程快很多
# Cpython解释器下
# GIL 全局解释器锁
# 保证了同一时刻下只有一个线程可以被CPU操作 # threading模块
# 创建子线程 Thread类
# start 开启子线程
# join 阻塞等待子线程结束
# setDeamon 设置守护线程
# 会等待主线程结束(包含所有非守护的子线程)之后守护线程才结束
# currentthread,enumerate,activecount
# 查看当前线程,所有的线程对象组成的列表,列表的长度
# from threading import Thread,currentThread
# def func():
# print(currentThread())
# for i in range(10):
# Thread(target=func).start()
今日内容
# 1.锁 ****
# 互斥锁
# 死锁现象
# 递归锁
# 2.其他模型 **
# 信号量
# 事件
# 条件
# 定时器
# 3.线程队列 ****
# 4.线程池模块 ****
# 锁是用来做什么的?
# 保证数据的安全的
# GIL是干什么的?
# 全局解释器锁线程
# 有了GIL还要锁干啥?
# 有了GIL还是会出现数据不安全的现象,所以还是要用锁
# import time
# from threading import Thread,Lock
# n = 100
# def func(lock):
# global n
# # n -= 1
# with lock:
# tmp = n-1 # n-=1
# time.sleep(0.1)
# n = tmp
#
# if __name__ == '__main__':
# l = []
# lock = Lock()
# for i in range(100):
# t = Thread(target=func,args=(lock,))
# t.start()
# l.append(t)
# for t in l:t.join()
# print(n)
dis模块使用
import dis
n = 1
def func():
n = 100
n -= 1 dis.dis(func) # 会出现线程不安全的两个条件
# 1.是全局变量
# 2.出现 += -=这样的操作 # 列表 字典
# 方法 l.append l.pop l.insert dic.update 都是线程安全的
# l[0] += 1
# d[k] += 1
死锁现象
# 科学家吃面问题
import time
from threading import Thread,Lock
# noodle_lock = Lock()
# fork_lock = Lock()
# 死锁不是时刻发生的,有偶然的情况整个程序都崩了
# 每一个线程之中不止一把锁,并且套着使用
# 如果某一件事情需要两个资源同时出现,那么不应该将这两个资源通过两把锁控制
# 而应看做一个资源
import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock(
def eat1(name):
noodle_lock.acquire()
print('%s拿到面条了'%name)
fork_lock.acquire()
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name) def eat2(name):
fork_lock.acquire()
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()
alex拿到面条了
alex拿到叉子了
alex开始吃面
alex放下叉子了wusir拿到叉子了
alex放下面了太白拿到面条了
发生了死锁
import time
from threading import Thread,Lock
lock = Lock()
def eat1(name):
lock.acquire()#只有一个锁,把资源都锁在一起
print('%s拿到面条了'%name)
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
lock.release()
print('%s放下叉子了' % name)
print('%s放下面了' % name) def eat2(name):
lock.acquire()
print('%s拿到叉子了' % name)
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
lock.release()
print('%s放下面了' % name)
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()
# 先临时解决
# 然后再找到死锁的原因,再去修改
from threading import RLock,Lock,Thread
# 互斥锁
# 无论在相同的线程还是不同的线程,都只能连续acquire一次
# 要想再acquire,必须先release
# 递归锁
# 在同一个线程中,可以无限次的acquire
# 但是要想在其他线程中也acquire,
# 必须现在自己的线程中添加和acquire次数相同的release
rlock = RLock()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
print('锁不住')
锁不住
lock = Lock()
lock.acquire()
print('1')
lock.acquire()
print('2')#不能打印2
rlock = RLock()
def func(num):
rlock.acquire()
print('aaaa',num)
rlock.acquire()
print('bbbb',num)
rlock.release()
rlock.release() Thread(target=func,args=(1,)).start()
Thread(target=func,args=(2,)).start()
aaaa 1
bbbb 1
aaaa 2
bbbb 2
import time
noodle_lock = fork_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print('%s拿到面条了'%name)
fork_lock.acquire()
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name) def eat2(name):
fork_lock.acquire()
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()
alex拿到面条了
alex拿到叉子了
alex开始吃面
alex放下叉子了
alex放下面了
wusir拿到叉子了
wusir拿到面条了
wusir开始吃面
wusir放下面了
wusir放下叉子了
太白拿到面条了
太白拿到叉子了
太白开始吃面
太白放下叉子了
太白放下面了
宝元拿到叉子了
宝元拿到面条了
宝元开始吃面
宝元放下面了
宝元放下叉子了
信号量
import time
from threading import Semaphore,Thread def func(name,sem):
sem.acquire()
print(name,'start')
time.sleep(1)
print(name,'stop')
sem.release() sem = Semaphore(5)
for i in range(20):
Thread(target=func,args=(i,sem)).start()
# 信号量和池
# 进程池
# 有1000个任务
# 一个进程池中有5个进程
# 所有的1000个任务会多次利用这五个进程来完成任务
# 信号量
# 有1000个任务
# 有1000个进程/线程
# 所有的1000个任务由于信号量的控制,只能5个5个的执行
事件
from threading import Event
# 事件
# wait() 阻塞 到事件内部标识为True就停止阻塞
# 控制标识
# set
# clear
# is_set # 连接数据库
import time
import random
from threading import Thread,Event
def connect_sql(e):
count = 0
while count < 3:
e.wait(0.5)
if e.is_set():
print('连接数据库成功')
break
else:
print('数据库未连接成功')
count += 1 def test(e):
time.sleep(random.randint(0,3))
e.set() e = Event()
Thread(target=test,args=(e,)).start()
Thread(target=connect_sql,args=(e,)).start()
条件
# wait 阻塞
# notify(n) 给信号
# 假如现在有20个线程
# 所有的线程都在wait这里阻塞
# notify(n) n传了多少
# 那么wait这边就能获得多少个解除阻塞的通知 # notifyall
# acquire
# release import threading def run(n):
con.acquire()
con.wait()
print("run the thread: %s" % n)
con.release() if __name__ == '__main__': con = threading.Condition()
for i in range(10):
t = threading.Thread(target=run, args=(i,))
t.start() while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()
print('****') # 设置某个条件
# 如果满足这个条件 就可以释放线程
# 监控测试我的网速
# 20000个任务
# 测试我的网速 /系统资源
# 发现系统资源有空闲,我就放行一部分任务
定时器
from threading import Timer def func():
print('执行我啦') t = Timer(3,func)
# 现在这个时间点我不想让它执行,而是预估一下大概多久之后它执行比较合适
t.start()
print('主线程的逻辑')
队列
import queue # 线程队列 线程之间数据安全
q = queue.Queue(1)
# 普通队列
q.put(1)
print(q.get())
try:
q.put_nowait(2)
except queue.Full:
print('您丢失了一个数据2')
print(q.get_nowait()) # 如果有数据我就取,如果没数据不阻塞而是报错
# 非阻塞的情况下
q.put(10)
print(q.get(timeout=2))
1
2
10
# 算法里 栈
lfq = queue.LifoQueue() # 栈
lfq.put(1)
lfq.put(2)
lfq.put(3)
print(lfq.get())
print(lfq.get())
print(lfq.get())
3
2
1
# 优先级队列,是根据第一个值的大小来排定优先级的
# ascii码越小,优先级越高
q = queue.PriorityQueue()
q.put((2,'a'))
q.put((0,'c'))
q.put((1,'b')) print(q.get()) # 线程+队列 实现生产者消费者模型
线程池
def func(num):
print('in %s func'%num,currentThread())
time.sleep(random.random())
return num**2 tp = ThreadPoolExecutor(5)
ret_l = []
for i in range(30):
ret = tp.submit(func,i)#运行时只有5个线程运行
ret_l.append(ret)
for ret in ret_l:
print(ret.result())
import time
import random
from threading import currentThread
from concurrent.futures import ThreadPoolExecutor as Pool import os
def func(num):
print('in %s func'%num,currentThread())
# print('in %s func'%num,os.getpid())
time.sleep(random.random())
return num**2
if __name__ == '__main__':
# tp = ThreadPoolExecutor(5)
tp = Pool(5)
ret_l = []
for i in range(30):
ret = tp.submit(func,i)
ret_l.append(ret)
tp.shutdown() # close + join
for ret in ret_l:
print(ret.result())
# 创建一个池
# 提交任务 submit
# 阻塞直到任务完成(close + join) shutdown
# 获取结果 result
# 简便用法 map
# 回调函数 add_done_callback
# 简便用法 map
import os
def func(num):
print('in %s func'%num,currentThread())
# print('in %s func'%num,os.getpid())
time.sleep(random.random())
return num**2
if __name__ == '__main__': # tp = ThreadPoolExecutor(5)
tp = Pool(5)
ret = tp.map(func,range(30))
for i in ret:
print(i)
# 回调函数 add_done_callback
def func1(num):
print('in func1 ',num,currentThread())
return num*'*' def func2(ret):
print('--->',ret.result(),currentThread())
tp = Pool(5)
print('主 : ',currentThread())
for i in range(10):
tp.submit(func1,i).add_done_callback(func2)
# 回调函数收到的参数是需要使用result()获取的
# 回调函数是由谁执行的? 主线程
# 相关概念
# 进程
# 线程
# GIL
# 很多模型
# 进程 锁(递归锁 互斥锁)\池(cpu的1-2倍)\队列
# 线程 锁(递归锁 互斥锁)\池(cpu个数的5倍)\队列 其他模型
day42 Pyhton 并发编程05的更多相关文章
- 并发编程 05—— Callable和Future
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池
Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...
- Java并发编程(05):悲观锁和乐观锁机制
本文源码:GitHub·点这里 || GitEE·点这里 一.资源和加锁 1.场景描述 多线程并发访问同一个资源问题,假如线程A获取变量之后修改变量值,线程C在此时也获取变量值并且修改,两个线程同时并 ...
- day38 Pyhton 并发编程
# 网络编程 # arp协议 : # 1.这是一个通过ip找mac地址的协议 # 2.由于有了socket,用户在使用网络的时候,只需要关心对方用户的ip地址就可以了 # 3.如果用户即将和这个ip进 ...
- day41 Pyhton 并发编程04
内容回顾 socket 最底层的网络通信 所有的网络通信都是基于socket 进程 什么是进程? 是操作系统的发展过程中,为了提高cpu的利用率,在操作系统同时运行多个程序的时候,为了数据的安 ...
- day43 Pyhton 并发编程06
一.内容回顾 线程 锁 为什么有了GIL之后还需要锁 多个线程同时操作全局变量还需要锁 当出现'非原子性操作',例如+= -= *= /= l.append(l) 原子性操作 a += 1 a= a ...
- day40 Pyhton 并发编程03
一.内容回顾 进程是计算机中最小的资源分配单位 进程与进程之间数据隔离,执行过程异步 为什么会出现进程的概念? 为了合理利用cpu,提高用户体验 多个进程是可以同时利用多个cpu的,可以实现并行的效果 ...
- day39 Pyhton 并发编程02 后
一.开启子进程的另一种方式 import os from multiprocessing import Process class MyProcess(Process): def __init__(s ...
- day39 Pyhton 并发编程02
一.内容回顾 并发和并行的区别 并发 宏观上是在同时运行的 微观上是一个一个顺序执行 同一时刻只有一个cpu在工作 并行 微观上就是同时执行的 同一时刻不止有一个cpu在工作 什么是进程 一个运行中的 ...
随机推荐
- CentOS如何设置IP连接网络
1.登录系统,进入:cd /etc/sysconfig/network-scripts 目录下,如下图: 找到 ifcfg-ens33(文件) 第二步:使用vi编辑器打开ifcfg-ens33文件,使 ...
- 初识ABP vNext(10):ABP设置管理
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 定义设置 使用设置 最后 前言 上一篇介绍了ABP模块化开发的基本步骤,完成了一个简单的文件上传功能.通常的模块都有一 ...
- maximo开发小结
maximo的后台开发 从0开始的 就把自己写的一些代码放者 1. setWhere 的效果是在原有的sql上添加一个and 以及这个条件mboSetRemote.setWhere("EN ...
- RabbitMQ安装、集群搭建、概念解析
RabbitMQ安装.集群搭建.概念解析 基本概念 为什么会产生MQ 1.解耦:采用异步方式实现业务需求达到解耦的目的. 2.缓冲流量,削峰填谷: 问:为什么会有流量冲击? 答:采用"直接调 ...
- Python安装与环境变量配置 入门详解 - 精简归纳
Python安装与环境变量配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 9 / 24 转载请注明出处!️ 目录 Python安装与环境变量配置 入门详解 - 精简归纳 一.下载Py ...
- HashMap,HashSet,HashTable,LinkedHashMap,LinkedHashSet,ArrayList,LinkedList,ConcurrentHashMap,Vector 区别
ConcurrentHashMap是弱一致性,也就是说遍历过程中其他线程可能对链表结构做了调整,因此get和containsKey返回的可能是过时的数据 ConcurrentHashMap是基于分段锁 ...
- BUU reverse xxor
下载下来的是个elf文件,因为懒得上Linux,直接往IDA里扔, 切到字符串的那个窗口,发现Congratulation!,应该是程序成功执行的表示, 双击,按'x',回车跟入 找到主函数: 1 _ ...
- ucore操作系统学习笔记(一) ucore lab1系统启动流程分析
一.ucore操作系统介绍 操作系统作为一个基础系统软件,对下控制硬件(cpu.内存.磁盘网卡等外设),屏蔽了底层复杂多样的硬件差异:对上则提供封装良好的应用程序接口,简化应用程序开发者的使用难度.站 ...
- 深入解析Vue里函数的调用顺序介绍
今天为大家分享一篇对vue里函数的调用顺序介绍,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. method用来定义方法的,比如你@click=& ...
- Centos-系统任务队列信息-uptime
uptime 显示系统的当前时间.系统从启动到当前运行时间.当前总共在线用户.系统1.5.15分钟负载情况