day38 各种队列、Event事件、协程、猴子补丁
1、各种队列
我们已经学习了队列这种存取值的方法,我们以前使用的队列是可以进行进程间通信的(IPC),但是今天学习的这两种队列是不能进行进程间通信的,只能进行线程间的通信
这两种队列分别是先进后出式队列Lifoqueue、优先级队列PriorityQueue
from queue import LifoQueue
lf = LifoQueue()
lf.put(111)
lf.put(222)
lf.put(333)
print(lf.get())
print(lf.get())
print(lf.get())
#
#
#
# 取值规则为先进后出
from queue import PriorityQueue
pq = PriorityQueue()
pq.put((1,2))
pq.put((1,3))
pq.put((1,4))
print(pq.get())
print(pq.get())
print(pq.get())
# (1,2)
# (1,3)
# (1,4)
# 规则是按照优先级进行对比,会先对比容器中的第一个元素,如果第一个一样则对比第二个元素,直至排出优先级
# 最高的那个元素
扩展知识: 大小比较的本质
关于为什么有的对象可以进行大小的比较,有的对象不能进行大小的比较
https://blog.csdn.net/zhangshuaijun123/article/details/82149056
2、Event事件
import time
from threading import Event, Thread
event = Event()
flag = False
def sever():
print("正在开启服务器...")
time.sleep(3)
print("服务器开启成功")
# global flag
# flag = True
event.set()
def client():
# print("正在连接...")
# if flag:
event.wait()
print("连接成功")
# else:
# print("连接失败")
# 假如我们想要在 服务器开启成功后在进行连接,用这种办法肯定不行,那么就需要在开启成功后添加一个标志,
# 只有在标志修改后直接进行后续步骤
# event就可以创建这种标志
t = Thread(target=sever)
t1 = Thread(target=client)
t.start()
t1.start()
print("over")
Event事件的作用是进行进程间通讯,将进程间进行状态的同步,我们可以在某个点设置event.set(),那么当其前方代码执行完毕后,就会发出一个信号,使得event.wait()方法不再阻塞,进而执行wait()之后的代码
3、协程
在我们使用多线程实现并发的过程中,如果并发量比较大,那么我们应该如何处理?
此时你可能会说开启多线程,但是如果并发量达到了百万或者千万级别,那应该如何呢?
此时使用多线程不可能实现,但是如果使用多进程+多线程可以进行处理,但是如果更多呢?
因为进程以及线程的开启数量是有限的,如果开启过多可能会造成系统不稳定,那么此时可以使用我们今天使用的内容 —— 协程
学习协程之前我们首先需要复习一下什么是并发,并发指的是在同一个时间段,看起来有几个进程在同时运行,但是实际上同一时间只有一个线程在执行,我们以前学了多线程实现并发,那么一个线程可不可以实现并发呢?
首先来看一下我们已经学过的生成器
import time
def func():
a = 1
for i in range(100000000):
a += 1
# yield
def func2():
# s = func()
a = 1
for i in range(100000000):
a += 1
# next(s)
st = time.time()
func()
func2()
print(time.time() - st)
# 在使用串行执行时,耗时为15秒,在使用生成器时,耗时为30秒
我们通过上述生成器的例子可以看出,在同一个进程中可以同时并发的执行两个函数,这已经实现了并发,但是,在上述例子中,并发虽然实现了,但是程序的执行效率却一点都没有提高,反而执行效率都降低了,
上述的例子,我们进行的都是数据的计算,那么如果我们将数据的计算换成IO操作呢?
可能你会想,实现IO操作也不行啊,因为即使达到了并行的效果,但是我们的程序在执行到IO操作时,还是会等待,只有在IO操作执行完毕才会进行后续的取值工作,这时候还是在进行等待,而且我们在进行多个函数之间的切换时,要写好多next取值的代码,整体逻辑也不清晰,那么有没有一种方法对这些进行了改变呢?
我们烦恼的问题,前人也遇到了,而且他们也进行了处理,有一个包叫做gevent,他可以帮我们处理这些烦人的问题
from gevent import monkey
monkey.patch_all()
import time
import gevent
def func():
print("func1 run")
time.sleep(3)
print("func1 over")
def func2():
print("func2 run")
time.sleep(5)
print("func2 over")
g1 = gevent.spawn(func)
g2 = gevent.spawn(func2)
gevent.joinall([g1,g2])
使用这个包可以将我们烦恼的问题全部解决,首先是进行等待的问题,在使用这个包进行单线程并发时,当一个函数遇到了IO操作,这个方法不会进行等待,而是直接切换到其他方法继续执行,因为对于操作系统来说最小的执行单位是线程,所以一个线程如果不进行IO操作,那么只有在这个时间片用完之后在进行进行切换,直接提高了我们使用CPU的时间,当我们使用gevent进行单线程并发时,如果遇到IO就切换到同线程下的其它函数进行执行,那么操作系统就不会将CPU切走,进而提高我们的程序对于CPU的使用
那么这个模块是如何实现这个不等待直接切换执行呢?
因为在这些IO操作中大部分都封装了不等待的方法,当时这些方法默认时开启的,如果设置为False,那么这些模块在进行执行时如果遇到了这些要进行IO操作,如果没有值就会报错,那么再将这些错误进行捕捉,再在except中进行切换就可以了
与此同时,新的疑问出现了,他是怎么将系统中的错误进行捕捉的呢?在我们的代码中并没有对这些错误进行处理,而且我们只是将这些函数作为参数传递给了这个模块进行执行
当我们将其中的monkey.patch_all()代码进行删除后,这些代码又会按照原来的执行方式进行执行了,这是因为这个monkey方法对这些产生阻塞的方法进行了偷梁换柱,已经将这些阻塞的方法换成了自己的代码,所以要将这段代码放在最上方,先导入其中的方法
4、猴子补丁
猴子补丁的原理是重新写带有阻塞的类中的方法,我们在使用猴子补丁时实际上已经把这些方法进行了覆盖
import json
import gevent
from gevent import monkey
monkey.patch_all()
def func(args):
print("这是一个假的方法")
def func1(args):
print("这是一个假的方法")
def my_patch():
json.load = func
json.loads = func1
my_patch()
json.loads("aaa")
json.load("aaa")
# 这是一个假的方法
# 这是一个假的方法
使用猴子补丁可以利用名称空间的查找规格将系统的方法屏蔽,将我们定义的方法覆盖覆盖原方法,然后再进行调用
day38 各种队列、Event事件、协程、猴子补丁的更多相关文章
- Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程
Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...
- day38——线程queue、事件event、协程
day38 线程queue 多线程抢占资源 只能让其串行--用到互斥锁 线程queue 队列--先进先出(FIFO) import queue q = queue.Queue(3) q.put(1) ...
- Day037--Python--线程的其他方法,GIL, 线程事件,队列,线程池,协程
1. 线程的一些其他方法 threading.current_thread() # 线程对象 threading.current_thread().getName() # 线程名称 threadi ...
- 异步、+回调机制、线程queue、线程Event、协程、单线程实现遇到IO切换
# from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import requests # import o ...
- python全栈开发 * 线程队列 线程池 协程 * 180731
一.线程队列 队列:1.Queue 先进先出 自带锁 数据安全 from queue import Queue from multiprocessing import Queue (IPC队列)2.L ...
- python 线程(其他方法,队列,线程池,协程 greenlet模块 gevent模块)
1.线程的其他方法 from threading import Thread,current_thread import time import threading def f1(n): time.s ...
- day 34 线程队列 线程池 协程 Greenlet \Gevent 模块
1 线程的其他方法 threading.current_thread().getName() 查询当前线程对象的名字 threading.current_thread().ident ...
- python 之 并发编程(线程Event、协程)
9.14 线程Event connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect from threading impor ...
- gevent协程之猴子补丁带来的坑
我们都知道使用gevent协程时,经常会看见在导入包的时候看见这样的代码 from gevent import monkey; monkey.patch_all() monkey.patch_all( ...
- Python 协程与事件循环
Table of Contents 前言 协程 async & await 事件循环 asyncio 的事件循环 结语 参考链接 前言 Python 标准库 asyncio 是我目前接触过的最 ...
随机推荐
- laravel 服务容器的用法
建立一个服务 <?php namespace App\Services; class FooService { public function __construct(){ } public f ...
- 【Python之路】特别篇--Django瀑布流实现
瀑布流 瀑布流,又称瀑布流式布局.是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部.最早采用此布局的网站是Pinteres ...
- am335x system upgrade usb wifi rtl8188eus(十九)
1 Scope of Document This document describes how to port rtl8188eus driver to linux 4.14.y desig ...
- sudo/su
linux用户分为根用户/ 普通用户 系统用户 根用户和普通用户是可以实际登录到系统中的,普通用户是没办法使用useradd添加新用户的,只有根用户有权限 当然,也可以使用su su 是切换用户的意思 ...
- 【原创】洛谷 LUOGU P3371 【模板】单源最短路径
P3371 [模板]单源最短路径 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出 ...
- XCTest-iOS单元测试框架
Xctest 是iOS的单元测试框架,有objective-c和swift两种语言可以选择 Xcuitest 是iOS的UI测试框架 XCTest 官方文档地址:https://devel ...
- codeforces163D
Large Refrigerator CodeForces - 163D 给定一个长方体的体积V,求出这个长方体的最小表面积. 输入 第一行有一个整数t (1 ≤ t ≤ 500) — 测试数据的组数 ...
- 【洛谷4001】 [ICPC-Beijing 2006]狼抓兔子(最小割)
传送门 洛谷 Solution 直接跑最小割板子就好了. 代码实现 #include<stdio.h> #include<stdlib.h> #include<strin ...
- redis的哨兵
删除旧master或者不可达slave sentinel永远会记录好一个Master的slaves,即使slave已经与组织失联好久了.这是很有用的,因为sentinel集群必须有能力把一个恢复可用的 ...
- Qt 插件学习(一)
插件是什么 注意:这儿暂时不考虑静态插件(潜意识中总觉得它根本就不算插件). 插件是一个动态库(共享库).动态库是一个独立的文件中的独立模块,可被多个程序访问. 先看动态库的两种用法 1. 程序链接时 ...