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密集型任务,对于本来就可以利用多核优势的场景下,这个就没必要开协程了
 
猴子补丁
就是把 原本阻塞的代码换成非阻塞的代码
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2019-06-06 16:35  轩辕12  阅读(110)  评论(0编辑  收藏  举报