热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

1同步调用异步调用+回调机制提交任务的两种方式:什么是同步异步任务执行的三种状态:同步调用vs阻塞,两种不同的等的效果异步回调******
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])

推荐阅读
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
author-avatar
缕足迹_124
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有