简单了解一下事件循环(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做了一个大概的了解。作为《前文》的补充


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

查看所有标签

猜你喜欢:

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

Masterminds of Programming

Masterminds of Programming

Federico Biancuzzi、Chromatic / O'Reilly Media / 2009-03-27 / USD 39.99

Description Masterminds of Programming features exclusive interviews with the creators of several historic and highly influential programming languages. Think along with Adin D. Falkoff (APL), Jame......一起来看看 《Masterminds of Programming》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具