Event Loops

事件循环

事件是由程序的一部分在特定条件下发出的消息,循环是在某种条件下完成并执行某个程序直到它完成的构造,因此,事件循环是一个循环,它允许用户订阅事件传输并注册处理程序/回调。 它使程序能够以异步方式运行。事件循环将它收到的所有事件委托给各自的回调,大多数回调模式的实现都有一个主要缺点,他们以引入大量嵌套的方式规定编程风格。因此,为了表示程序的某些部分彼此依赖,我们使用排序,然而,在依赖于异步结果的情况下,出现了以下模式:

  • 嵌套回调,以便内部回调可以访问外部回调的结果(闭包)
  • 使用充当未来结果代理的对象(所谓的 Future 或 Promise )
  • 协程,它是在事件循环中运行的可挂起函数

Nesting Callback(嵌套回调)

嵌套回调的经验法则是,如果需要等待回调的结果,则必须将代码嵌入到相应的回调中。你很快就会陷入臭名昭着的回调地狱般的局面。回调地狱是回调嵌套的深度,这使得程序的推理和改进成为一种噩梦。

Futures/Promises

Futures/Promises 是封装异步调用的结果和错误处理的对象。它们最终会提供 APIs 来查询results/exceptions 的当前状态,以及注册回调来处理 results/exceptions 的方法。由于它们封装了异步调用的未来上下文并需要嵌套,因此生成的程序似乎以更自上而下的方式编写。(.then那种形式)

Coroutines

你可以简单把协程理解为可以中断的函数。暂停意味着我们可以在函数任何位置暂停协程。这意味着它一定有某种原子单位组成。这就是我们所说的 tick,也就是我们所测量的 tick。tick 是事件循环的时间单位, 它包含在事件循环的一个迭代步骤中发生的所有操作

协程实际上可以做得更多:它们可以暂停自己并等待另一个协同程序的结果。

waiiting 的所有逻辑由事件循环协调,因为它知道相应的协程状态

Asyncio中事件循环的生命周期

asyncio中的事件循环有四种状态:

1.Idle

2.Running

3.Stopped

4.Closed

您可以通过四种事件循环方法与事件循环的生命周期进行交互,这些方法可以分为启动,停止和关闭方法。 它们构成了事件循环生命周期接口,所有 asyncio /第三方事件循环都需要提供兼容性。

1.run_forever

2.run_until_complete

调用 run_forever 方法时没有参数,而 run_until_complete 方法需要传入一个协程函数作为参数。要停止,我们可以使用 stop 方法;要关闭,我们使用 close 方法。

The Idle State(空闲状态)

空闲状态是创建循环后所处的状态。在此状态下不消耗任何协程或者回调函数。在这个状态下 loop.is_running 返回 False。

The Running State(运行状态)

运行状态是在调用 loop.run_forever 或 loop.run_until_complete 之后循环所处的状态。在这个状态下 loop.is_running 返回 True。

这些方法之间的区别在于,在 loop.run_until_complete 的情况下,loop.run_until_complete 会将协程被包装在 asyncio.Future

中。回调在 asyncio.Future 对象上注册为处理程序,该对象在完全消耗协程后运行loop.stop 方法。

The Stopped State(停止状态)

停止状态是调用stop命令后循环所处的状态。调用stop方法后,调用is_running方法不会返回False,首先消耗所有挂起的回调。只有在它们被消耗之后,循环才会进入空闲状态。

The Closed State(关闭状态)

循环通过调用close方法进入关闭状态。只有当循环不处于运行状态时,才能调用它。

事件循环的基本类

在Python 3中默认提供两种事件循环。

抽象事件循环类由asyncio.events和asyncio.base_events模块提供。

AbstractEventLoop和BaseEventLoop表示事件循环实现的两个潜在类。

AbstractEventLoop

AbstractEventLoop类定义了原生asyncio中事件循环的接口。

接口方法可以大致分为以下几个部分

  • 生命周期方法(运行、停止、查询状态和关闭循环)
  • 调度方法
  • 回调
  • 协程
  • 创建Future对象
  • 线程相关的方法
  • IO操作相关的方法
  • 低层级API(socket, pipe, and reader/writer APIs)
  • 高层级APIs(server, pipe, and subprocess-related methods)
  • 信号方法
  • 调试标志管理方法

该应用编程接口是稳定的,在手动事件循环实现的情况下可以被子类化

BaseEventLoop

尽管基于更高级别的组件,但不应使用BaseEventLoop类来创建手动循环实现,因为它的API不稳定。 但它可以作为一个如何实现接口的指南。

它的BaseEventLoop._run_once方法在循环的每个tick上调用,因此包含一次迭代所需的所有操作。这将调用所有当前准备好的回调,I/O轮询,调度生成的回调,然后调度call_later回调,如果您计划自己实现事件循环,则需要提供与其类似的方法,函数的名称和主体只是实现细节。

事件循环是特定于操作系统的吗?

是的,事件循环是特定于操作系统的 这可能会影响API可用性和事件循环的速度。 例如,add_signal_handler和remove_signal_handler是仅限UNIX的循环API。

除了缺少相应的本机绑定之外,操作系统特性背后的原因之一是大多数环路都是基于selectors模块实现的。selectors是基于select模块的提高的高级I/O多路复用接口。

selectors模块建立在Select, poll, devpoll, epoll, or kqueue之上,具体取决于底层操作系统。selectors模块中的模块负责设置默认选择器,而默认选择器又被异步模块使用。

if 'KqueueSelector' in globals():
DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
DefaultSelector = EpollSelector
elif 'DevpollSelector' in globals():
DefaultSelector = DevpollSelector
elif 'PollSelector' in globals():
DefaultSelector = PollSelector
else:
DefaultSelector = SelectSelector

注意在Windows中还有一个基于I/o完成端口或短IoCP的ProactorEventLoop类实现

IOCP的官方文件将它们描述为“在多处理器系统上处理多个异步输入输出请求的有效线程模型”。例如,如果需要使用asyncio子进程API,可以在Windows上使用ProactorEventLoop。

后续,会不断完善。

更多精彩内容请关注公众号:python学习开发

协程系列之Event Loops的更多相关文章

  1. 深入理解协程(二):yield from实现异步协程

    原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的第二篇. yield from ...

  2. 深入理解协程(三):async/await实现异步协程

    原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...

  3. 深入理解协程(四):async/await异步爬虫实战

    本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...

  4. 异步、+回调机制、线程queue、线程Event、协程、单线程实现遇到IO切换

    # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import requests # import o ...

  5. python系列7进程线程和协程

    目录 进程 线程 协程  上下文切换 前言:线程和进程的关系图 由下图可知,在每个应用程序执行的过程中,都会去产生一个主进程和主线程来完成工作,当我们需要并发的执行的时候,就会通过主进程去生成一系列的 ...

  6. (day31) Event+协程+进程/线程池

    目录 昨日回顾 GIL全局解释器锁 计算密集型和IO密集型 死锁现象 递归锁 信号量 线程队列 FOFI队列 LIFO队列 优先级队列 今日内容 Event事件 线程池与进程池 异步提交和回调函数 协 ...

  7. Event事件、进程池与线程池、协程

    目录 Event事件 进程池与线程池 多线程爬取梨视频 协程 协程目的 gevent TCP服务端socket套接字实现协程 Event事件 用来控制线程的执行 出现e.wait(),就会把这个线程设 ...

  8. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

  9. day38——线程queue、事件event、协程

    day38 线程queue 多线程抢占资源 只能让其串行--用到互斥锁 线程queue 队列--先进先出(FIFO) import queue q = queue.Queue(3) q.put(1) ...

随机推荐

  1. 三、maven学习-高级

    maven父子工程

  2. DDOS攻击脚本

    import sysimport osimport timeimport socketimport random#Code Timefrom datetime import datetimenow = ...

  3. java实现spark常用算子之Reduce

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.a ...

  4. Typora入门:全网最全教程

    目录 简介 Markdown介绍 常用快捷键 块元素 换行符 标题级别 引用文字 无序列表 有序列表 任务列表 代码块 数学表达式 插入表格 脚注 分割线 目录(TOC) 跨度元素 链接 网址 图片 ...

  5. day12 css样式

    目录 1.标签分类   2.浮动布局   3.margin塌陷   4.定位postion   5.背景图 一. 标签分类 默认在标准文档流 行内标签 span,a,em,i,strong,b,inp ...

  6. JAVA 分布式

    什么是分布式系统? 要理解分布式系统,主要需要明白一下2个方面: 1.分布式系统一定是由多个节点组成的系统. 其中,节点指的是计算机服务器,而且这些节点一般不是孤立的,而是互通的. 2.这些连通的节点 ...

  7. Tomcat----服务运行的容器

    在介绍Tomcat之前,我们先介绍一个概念Servlet. Servlet是一个运行在WEB服务器上的小的Java程序,用来接收和响应从客户端发送过来的请求,通常使用HTTP协议.从下图可以看出Ser ...

  8. JavaScript设计模式与开发实践(二)——apply&&call

    call和apply的用途 改变this指向 先看个例子: var obj1 = { name: 'sven' }; var obj2 = { name: 'anne' }; window.name ...

  9. 解决laydate动态设置初始值的问题

    //初始化//注意:我这里是时间范围选择,所以定义了range属性.var timeScope = laydate.render({ elem: '#time_scope', range: '~', ...

  10. php类相关知识----类常量,静态变量

    类常量 <?php class myuser { ;//定义的常量不带$符号,常量之前没有访问修饰符,常量之前没有修饰符号 public function monolog() { echo &q ...