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_foreverloop.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. webmagic学习之路-3:采集安居客经纪人详情页

    这里希望安居客的同行的轻喷!!单纯的做测试,玩玩. 就这么糟践你们的服务器了!!!sorry! 这次学会了webmagic 设置处理的访问HTML返回代码,因为之前一直404的页面process根本都 ...

  2. luogu题解P2486[SDOI2011]染色--树链剖分+trick

    题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在 ...

  3. ftp卡死问题

    最近用org.apache.commons.net.ftp.FTPClient  写ftp的上传下载的定时任务 发现有时候线程会卡住,也不报错就一直不工作了,后来发现需要使用ftp的被动模式才行,实现 ...

  4. ES6新增内容总结

    ES6新增内容有:1,模块化思想.2,关于变量let和const.3,解构赋值.4,字符串的扩展.5,函数的扩展.6,箭头函数.7,继承apply的用法 以下就是详解: 1:模块化思想 非模块化有命名 ...

  5. Sql Server 导出数据库表结构的SQL查询语句

    --导出数据库所有表 SELECT 表名 Then D.name Else '' End, 表说明 Then isnull(F.value,'') Else '' End, 字段序号 = A.colo ...

  6. git统计某个时间段写的代码行数

    1. 任务需要 领导想每个迭代统计一下,当前迭代开发的代码数量是多少 2. 解决方法 git log --stat --since=2019-09-12 --until=2019-09-27 | pe ...

  7. SQL Server 2005 实现数据库同步备份 过程--结果---分析

    数据库复制:   简单来说,数据库复制就是由两台服务器,主服务器和备份服务器,主服务器修改后,备份服务器自动修改. 复制的模式有两种:推送模式和请求模式,推送模式是主服务器修改后,自动发给备份服务器, ...

  8. 【3】Zookeeper中的角色

    一.Zookeeper角色的分类 领导者(leader) Leader服务器为客户端提供读服务和写服务. 学习者(learner) 跟随者(follower) Follower服务器为客户端提供读服务 ...

  9. Delphi TIdUDPClient组件

  10. Webpack编译提示内存溢出解决方案

    在项目开发中,随着业务需求的复杂项目随之增大,再加上同一个文件被引用次数过于频繁在开发编译或者上线打包时经常会出现如下错误: 这个报错的意思就是Node内存不足所导致的,我们都知道 Node 是基于V ...