day38
day38
在线程池和进程池中,每次提交任务,都会返回一个表示任务的对象FUture对象
Future对象具体一个绑定方法,add_done_callback用于指定的回调函数
如何直接使用thread的话,如何完成回调
def call_back(res)
print("%s" % res)
def task(callback):
print("run")
return 100
res = 100
callback(res) #执行回调函数,并传入任务结果
t = Thread(target=task,args=(call_back,))#调上面那个函数
t.start()
异步回调原理
??????在发起任务时候,传入一个函数(call_back)作为回调函数,在任务完成后,执行该函数,并将执行结果作为参数(callback)传入
如果是进程的回调,还需要考虑数据通讯的问题,最难的是让父进程在拿到结果的时候立即触发回调的函数的执行,父进程不应该卡住.
###今日内容
1.线程一堆队列
Queue
lifoqueue后进先出队列 顺序不一样
prioityQueue具备优先级的队列 (可以存储一个可迭代对象,可以比较大小) 优先级高(值越小,字符串也可以)的先出 ,自定义对象不能使用比较运算符,不能存储
2.事件event
表示发生了某些事情,可以去关注某个事件,采取一些行动.
事件本质上是用来线程间通讯,用于状态同步.
案例:
有两条线程,一个用于启动服务器,一个是用户客户端连接到服务器.
条件是服务器启动成功,客户端才能连接成功.
#代码
爬虫,开视频窗口,数量小于5就开,大于5就不开.
while True:
判断视频的窗口是否为5:
true:event.clear()
false:event.set()
3.协程*****
协程的目的就是要在单线程的实现并发
单线程实现并发
并发:多个任务看起来是同时运行,本质是切换+保存状态
生成器中yield就可以保存当前函数的运行状态,
def func1():
yield
res = func1()
next(res)
##代码
并发代码
import time
def func1():
a = 1
for i in range(11111111111):
a+=1
yield
def func2():
res = func1()
a = 1
for i in range(11111111111):
a+=1
next(res)
st = time.time()
func2()
print(time.time()-st)
#串行代码
经过测试,单线程并发并不能提高性能,对于计算密集型任务而言
对于IO操作而言,必须要具备检测IO操作 并自动切换成其他任务.这才能真正的提高效率.
greenlet
直接使用yiled可以并发,但是代码结构太乱,
????????
gevent
##什么是协程
轻量级线程,也称之为微线程,是应用程序级别的任务调度方式
应用程序级别调度:检测到IO操作时,立马切换到我的其他任务来执行,如果有足够的任务来执行,就可以
把cpu的时间片充分利用起来.
操作系统级别的调度:遇到IO操作系统就回拿走cpu,下次分给哪个进程就不一定了
线程,最小执行单位,可以解决一定数量的并发问题,但是如果线程数量达到上限,后续任务必须等待.
对于IO密集型任务,最好的方式就是一个线程处理所有任务,
########cpython如何提高效率
在cpthon中有GIL锁导致多线程不能并行执行,丧失了多核优势,即使开启了多线程,也只能并发,
这个时候完全可以使用协程来实现并发,优点:不会占用更多的无用资源
缺点:如果是计算任务,使用协程反而降低效率
在cpython中要想效率最高,多进程+单线程+协程.如果这个都不行,只能集群分布式了.
终极杀招:对IO密集型任务
在系统中可承受的范围内,开启多进程
在进程下开启多个协程任务
def task1():
print("taks1 run")
#gevent.sleep(3) #需要加猴子补丁,去检测IO
print("task1 over")
def task1():
print("taks2 run")
print("task2 over")
g1 = gevent.spawn(task1)
g2 = gevent.spawn(task2)
gevent.joinall([g1,g2])
使用spawn来创建一个协程任务,想要任务执行,必须保证主线程没挂,因为所有的协程任务都是主线程在执行,必须调用join来等待协程任务,理论上等待执行时间最长的任务就行,但是不清楚谁的时间长,所以,可以全部等
gevent不具备检测IO的能力,需要用猴子为他打补丁,打补丁之后就能检测IO(需要写到最上面去,必须保证导入模块前,就打完补丁)
使用场景:cpython下IO密集型任务,对于本来就可以利用多核优势的场景下,这个就没必要开协程了
猴子补丁
就是把 原本阻塞的代码换成非阻塞的代码