简单了解一下事件循环(Event Loop)
关于我
一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。
Github:https://github.com/hylinux1024
微信公众号:终身开发者(angrycode)
0x00 事件循环(Event Loop)
在前文《为何你还不懂得如何使用Python协程
》 中提到协程是通过asyncio包中的高级API来启动的。而asyncio模块中的核心就是事件循环(Event Loop)。它可用于执行异步任务、事件回调、执行网络IO操作和运行子进程。官方的文档也是建议开发者应该尽量使用asyncio包提供的高级的API,避免直接使用Event Loop对象中的方法。
系统提供的底层能力的功能模块例如网络连接、文件IO等都会使用到loop。
大多数情况下,这些高级API可以满足众多使用场景,但作为一个有追求的猿类,应该要有一点点探索的精神,看看在asyncio封装之下的Event Loop。
获取Event Loop对象
asyncio.get_running_loop()
获取当前系统线程正在使用的loop对象asyncio.get_event_loop()
获取当前正在使用的loop对象。如果当前系统线程还没有loop对象,那么就会创建一个新的loop对象,并使用asyncio.set_event_loop(loop)方法设置到当前系统线程中。asyncio.new_event_loop()
创建一个新的loop对象asyncio.set_event_loop(loop)
将loop设置成系统线程使用的对象
Event Loop对象的常用方法
如果使用类似asyncio.run()这些高级API,以下这些方法,基本上很少会用到,建议通读一下,大概知道loop对象拥有哪些API,了解以下底层的实现细节。
启动和停止
loop.run_until_complete(future)
future对象执行完成才返回loop.run_forever()
一直运行,直到调用了loop.stop()方法loop.stop()
停止loop对象loop.is_running()
判断loop是否正在运行loop.is_closed()
判断loop是否关闭loop.close()
关闭loop对象coroutine loop.shutdown_asyncgens()
try:
loop.run_forever()
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
回调方法
loop.call_soon(callback, *args, context=None)
在事件循环的下一次迭代中执行callback方法,args是方法中的参数loop.call_soon_threadsafe(callback, *args, context=None)
线程安全的call_soon()
iimport asyncio
import time
def hello_world(loop):
print('Hello World')
time.sleep(3) # 模拟长时间操作
loop.stop()
loop = asyncio.get_event_loop()
# 使用loop执行 hello_world()
loop.call_soon(hello_world, loop)
# 会一直阻塞,直到调用了stop方法
try:
loop.run_forever()
finally:
loop.close()
可延迟的回调方法
可设置延迟执行的方法
loop.call_later(delay, callback, *args, context=None)
延迟delay秒后执行loop.call_at(when, callback, *args, context=None)
在指定时间点执行loop.time()
返回当前时间
import asyncio
import datetime
def display_date(end_time, loop):
print(datetime.datetime.now())
if (loop.time() + 1.0) < end_time:
# 1秒后执行
loop.call_later(1, display_date, end_time, loop)
else:
loop.stop()
loop = asyncio.get_event_loop()
# 执行5秒
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)
# 一直运行,等待stop的调用
try:
loop.run_forever()
finally:
loop.close()
执行结果打印5秒时间点
2019-05-09 22:34:47.885412
2019-05-09 22:34:48.887513
2019-05-09 22:34:49.889396
2019-05-09 22:34:50.894316
2019-05-09 22:34:51.898457
创建Future和Tasks
loop.create_future()
创建一个绑定事件循环的future对象loop.create_task(coro)
将coro放入调度,并返回task对象loop.set_task_factory(factory)
设置任务工厂loop.get_task_factory()
返回任务工厂,有可能返回None
创建网络连
coroutine loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None)
指定host、port等参数创建网络连接
coroutine loop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_address=None, reuse_port=None, allow_broadcast=None, sock=None)
创建UDP连接
coroutine loop.create_unix_connection(protocol_factory, path=None, *, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)
创建Unix连接
coroutine loop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)
创建TCP服务
coroutine loop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)
创建Unix服务
coroutine loop.connect_accepted_socket(protocol_factory, sock, *, ssl=None, ssl_handshake_timeout=None)
封装已建立的连接,返回元组(transport, protocol)
Event Loop 的实现
asyncio 的事件循环有两种不同的实现:SelectorEventLoop和 ProactorEventLoop,它们的父类是AbstractEventLoop
SelectorEventLoop
这个是asyncio默认使用的Event Loop实现,支持unix和windows平台
import asyncio
import selectors
selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)
ProactorEventLoop
这个是Windows平台专有的实现
import asyncio
import sys
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
0x01 总结
事件循环是asyncio的核心,asncio模块的很多高级接口是通过封装Event Loop对象来实现的。它提供了执行异步任务、事件回调、执行网络IO操作和运行子进程的能力。
本文是通过官方文档对事件循环的概念和它的常见API做了一个大概的了解。作为《前文》的补充
0x02 引用
简单了解一下事件循环(Event Loop)的更多相关文章
- JS事件循环(Event Loop)机制
前言 众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言. 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选 ...
- 事件循环 event loop 究竟是什么
事件循环 event loop 究竟是什么 一些概念 浏览器运行时是多进程,从任务管理器或者活动监视器上可以验证. 打开新标签页和增加一个插件都会增加一个进程,如下图:  浏览器渲染进程是多线程,包 ...
- 事件循环Event loop到底是什么
摘要:本文通过结合官方文档MDN和其他博客深入解析浏览器的事件循环机制,而NodeJS有另一套事件循环机制,不在本文讨论范围中.process.nextTick和setImmediate是NodeJS ...
- JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念
说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的? ...
- 浏览器与Node的事件循环(Event Loop)有何区别?
前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的. 一.线程与进程 1. 概念 我们经常说 JS 是单线程执行的,指的是一个进程里 ...
- JavaScript 事件循环 — event loop
引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...
- 一文梳理JavaScript 事件循环(Event Loop)
事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个 ...
- JavaScript事件循环(Event Loop)机制
JavaScript 是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决定 ...
- 事件循环Event Loop
在 事件循环 期间的某个时刻,运行时会从最先进入队列的消息开始处理队列中的消息.被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数.正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧. ...
随机推荐
- 微信小程序 setData 数组 渲染问题 删除之后的数组渲染不正确
list: [ { id: , mode: , src: ' }, { id: , mode: , src: ' }, { id: , mode: , src: ' } ], onDelete(e) ...
- 个人永久性免费-Excel催化剂插件功能修复与更新汇总篇之九
第11波-快速批量插入图片并保护纵横比不变 原文链接:https://www.jianshu.com/p/9a3d9aa7ba7e 修复了插入图片有纵向的图片时,插入后还是显示横向的情况. 第83波- ...
- 个人永久性免费-Excel催化剂功能第48波-拆分工作薄内工作表,堪称Excel界的单反
一个工作薄有多个相同类型的工作表,然后想通过批量操作,把每个工作表都另存为一个工作薄文件,这个批量拆分工作薄,绝大多数插件都有此功能,就如懂点VBA的高级用户也常常有点不屑于用插件来完成,自己写向行V ...
- c语言进阶8-数据结构
一. 数据结构的起源: 1. 为什么要学习数据结构 阿基米德说过:“给我一个支点,我就能翘起地球”.那么给我一个程序,我就能用好程序,给我一个结构,我就能把内容填充完成.打个比方,一个 ...
- 客户端内嵌Vue页面
目前很多应用都存在网页端和客户端形式,例如常用的:钉钉.微信等.按传统的开发形式,需要为客户端开发一套界面.基于当前Web应用可以利用三大前端框架和UI框架快速开发出各种酷炫的界面,于是出现了客户端嵌 ...
- 《 C#语言学习笔记》——自动属性
属性是访问对象状态的首选方式,因为它们禁止外部代码实现对象内部的数据存储机制.属性还对内部数据的访问方式有了更多控制.一般以非常标准的方式定义属性,即通过一个公共属性直接访问一个私有成员. 利用自动属 ...
- 盘一盘 synchronized (一)—— 从打印Java对象头说起
Java对象头的组成 Java对象的对象头由 mark word 和 klass pointer 两部分组成, mark word存储了同步状态.标识.hashcode.GC状态等等. klass ...
- python课堂整理15---map, filter,reduce函数
一.map函数 处理序列(可迭代对象)中的每一个元素,得到的结果是一个‘列表’(其实是个迭代器),该‘列表’元素个数及位置与原来一样 理解下面这段代码: num_l = [1, 2, 4, 6] de ...
- [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解
[PXE] Linux(centos6)中PXE 服务器搭建,PXE安装.启动及PXE理论详解 本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议 ...
- DDMS 视图 Emulator Control 为灰色
Emulator Control 模拟发送短信时,发现所有选项均为灰色,如图所示: 解决方法: 确认以下四种情形或方法 已测试 Genymotion 模拟器和真机均不行,而Eclipse自带模拟器可以 ...