热门标签 | 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])

推荐阅读
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 这篇文章主要介绍了Python拼接字符串的七种方式,包括使用%、format()、join()、f-string等方法。每种方法都有其特点和限制,通过本文的介绍可以帮助读者更好地理解和运用字符串拼接的技巧。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
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社区 版权所有