简单了解一下事件循环(Event Loop)

栏目: 编程工具 · 发布时间: 5年前

内容简介:在前文系统提供的底层能力的功能模块例如网络连接、文件IO等都会使用到大多数情况下,这些高级

在前文 《为何你还不懂得如何使用 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)
复制代码

指定 hostport 等参数创建网络连接

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 的事件循环有两种不同的实现: SelectorEventLoopProactorEventLoop ,它们的父类是 AbstractEventLoop

SelectorEventLoop

这个是 asyncio 默认使用的 Event Loop 实现,支持 unixwindows 平台

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做了一个大概的了解。作为《前文》的补充


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

重构

重构

[美]马丁•福勒(Martin Fowler) / 熊节 / 人民邮电出版社 / 2015-8 / 69.00

本书清晰揭示了重构的过程,解释了重构的原理和最佳实践方式,并给出了何时以及何地应该开始挖掘代码以求改善。书中给出了70 多个可行的重构,每个重构都介绍了一种经过验证的代码变换手法的动机和技术。本书提出的重构准则将帮助你一次一小步地修改你的代码,从而减少了开发过程中的风险。一起来看看 《重构》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试