同步调用 异步调用+回调机制

1 同步调用 异步调用+回调机制
提交任务的两种方式:
什么是同步异步
任务执行的三种状态:
同步调用vs阻塞,两种不同的'等'的效果

异步回调 ******
什么是异步回调?
为什么需要回调?(比如 烧水壶,水烧开后 水壶会发出响声)
注意点:
回调函数什么时候被执行?
谁在执行回调函数?
线程的异步回调

同步:
#所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。
按照这个定义,其实绝大多数函数都是同步调用。但是一般而言,
我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
#举例:
#1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束,
根本不考虑任务是在计算还是在io阻塞,总之就是一股脑地等任务结束
#2. concurrent.futures.ProcessPoolExecutor().submit(func,).result()
#3. concurrent.futures.ThreadPoolExecutor().submit(func,).result()

异步:
#异步的概念和同步相对。当一个异步功能调用发出后,调用者不能立刻得到结果。
当该异步功能完成后,通过状态、通知或回调来通知调用者。如果异步功能用状态来通知,
那么调用者就需要每隔一定时间检查一次,效率就很低
(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一 种很严重的错误)。
如果是使用通知的方式,效率则很高,因为异步功能几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。
#举例:
#1. multiprocessing.Pool().apply_async() #发起异步调用后,并不会等待任务结束才返回,
相反,会立即获取一个临时结果(并不是最终的结果,可能是封装好的一个对象)。
#2. concurrent.futures.ProcessPoolExecutor(3).submit(func,)
#3. concurrent.futures.ThreadPoolExecutor(3).submit(func,)

阻塞:
#阻塞调用是指调用结果返回之前,当前线程会被挂起(如遇到io操作)。
函数只有在得到结果之后才会将阻塞的线程激活。有人也许会把阻塞调用和同步调用等同起来,
实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
#举例:
#1. 同步调用:apply一个累计1亿次的任务,该调用会一直等待,
直到任务返回结果为止,但并未阻塞住(即便是被抢走cpu的执行权限,那也是处于就绪态);
#2. 阻塞调用:当socket工作在阻塞模式的时候,
如果没有数据的情况下调用recv函数,则当前线程就会被挂起,直到有数据为止。

非阻塞:
#非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程。

小结:
#1. 同步与异步针对的是函数/任务的调用方式:同步就是当一个进程发起一个函数(任务)调用的时候,
一直等到函数(任务)完成,而进程继续处于激活状态。而异步情况下是当一个进程发起一个函数(任务)调用的时候,
不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件等方式通知进程任务完成。
#2. 阻塞与非阻塞针对的是进程或线程:阻塞是当请求不能满足的时候就将进程挂起,而非阻塞则不会阻塞当前进程


2.线程队列 ***
队列
堆栈
优先级队列

3、单线程下实现并发(***)
什么是协程
并发
并发实现的本质=切换+保存状态(两类切换)
高性能分析:
为什么需要协程
如何实现协程(三种)
协程的应用场景:
总结点:




====================================
1 同步调用 异步调用+回调机制
提交任务的两种方式:
同步调用 :提交任务必须等待任务完成,才能执行下一行
异步调用 :提交任务不需要等待任务完成,立即执行下一行

线程任务执行的三种状态:
阻塞
阻塞 遇到了IO操作 失去了CPU的执行权
非阻塞:
就绪
运行

同步调用vs阻塞,两种不同的'等'的效果
同步调用的等 比如经过上千亿次计算,运行时间过长导致,被操作系统拿走执行权限,处于就绪态,非阻塞
阻塞的等 比如经过IO操作,sleep了100秒,这是阻塞

异步回调 ******
什么是异步回调?
发起了一个异步任务 子线程或子进程任务完成后 调用一个函数来通知任务发起方
为什么需要回调?(比如 烧水壶,水烧开后 水壶会发出响声)
由于任务是异步执行 任务发起方不知道啊什么时候完成
所以使用回调的方式告诉发起方任务执行结果 其他方式也可以将数据交还给主进程
1.shutdown 主进程会等到所有任务完成 # 类似于join的功能pool.shutdown(wait=True)
2.result函数 会阻塞直到任务完成
都会阻塞 导致效率降低 所以使用回调
注意点:
回调函数什么时候被执行? 子进程任务完成时
谁在执行回调函数? 主进程
线程的异步回调:
使用方式都相同 唯一的不同是执行回调函数 是子线程在执行
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor

pool = ThreadPoolExecutor()
def get_data_task(url):
return text
def parser_data(f):
print(f.result())
if __name__ == '__main__':
f = pool.submit(get_data_task,url) #get_data_task生产数据
f.add_done_callback(parser_data) #parser_data处理数据

2.线程队列 *** 见38复习
队列
堆栈
优先级队列

3、单线程下实现并发(***)
什么是协程:
单线程下实现并发,在应用程序级别实现多个任务之间切换+保存状态
并发:看起来是同时运行
并发实现的本质=切换+保存状态
切换:
1、遇到IO阻塞会切换(可以提升运行效率)
2、占用cpu时间过长或者有一个优先级更高的任务抢走了cpu
优点:
1.协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因为更加轻量级
2.单线程内就可以实现并发的效果,最大限度地利用cpu
缺点:
1.协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程下开启协程
2.协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

高性能分析:
单纯地切换,或者说么有遇到io操作也切换,反而会降低效率
检测单线程下的IO行为,实现遇到IO立即切换到其他任务执行

为什么用协程? 多线程实现并发 有什么问题?
TCP程序中 处理客户端的连接 需要子线程 但是子线程依然会阻塞
一旦阻塞 CPU切走 但是无法保证是否切到当前程序
提高效率的解决方案 是想办法尽可能多的占用CPU
当程序遇到阻塞时 切换到别的任务 注意使用程序内切换


协程的实现
1 yield 把函数做成了生成器 生成器会自动保存状态
2 greenlet 帮我们封装yield 可以实现任务切换
创建对象时 制定任务就是函数 在函数中手动来switch切换任务 不能检测到IO行为
3 gevent 封装了grennlet 既能够切换执行 也能检测IO

使用gevent需要配合monkey补丁 monkey补丁内部将原本阻塞的模块 替换为了非阻塞的
monkey必须放在导入(需要检测IO的模块)模块之前
monkey.patch_all()
gevent核心函数spawn(函数名)
join让主线程等待所有任务执行完成才结束

协程的应用场景:
(没有IO绝对不使用协程) TCP 多客户端实现方式
1.来一个客户端就来一个进程 资源消耗较大
2.来一个客户端就来一个线程 也不能无限开
3.用进程池 或 线程池 还是一个线程或进程只能维护一个连接
4.协程 一个线程就可以处理多个客户端 遇到io就切到另一个

总结协程特点:
必须在只有一个单线程里实现并发,(将io阻塞时间用于执行计算 可以提高效率 原理:一直使用CPU直到超时)
修改共享数据不需加锁
用户程序里自己保存多个控制流的上下文栈
附加:一个协程遇到IO操作自动切换到其它协程
(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))


from gevent import monkey;monkey.patch_all()
import gevent

def eat():
print('eat food 1')
time.sleep(2)
print('eat food 2')
def play():
print('play 1')
time.sleep(1)
print('play 2')
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
gevent.joinall([g1,g2])

转载于:https://www.cnblogs.com/du-jun/p/9963301.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值