asyncio 系列五、asyncio的事件循环

官网连接:https://docs.python.org/zh-cn/3.7/library/asyncio-eventloop.html#asyncio.loop.run_in_executor

 

事件循环是每个 asyncio 应用的核心。 事件循环会运行异步任务和回调,执行网络 IO 操作,以及运行子进程。里面封装的方法用于上层函数调用。本节所针对的主要是低层级代码、库和框架的编写者,他们需要更细致地控制事件循环行为。

一、获取事件循环

asyncio.get_running_loop()

返回当前 OS 线程中正在运行的事件循环。

如果没有正在运行的事件循环则会引发 RuntimeError。 此函数只能由协程或回调来调用。

 

asyncio.get_event_loop()

获取当前事件循环。 如果当前 OS 线程没有设置当前事件循环并且 set_event_loop() 还没有被调用,asyncio 将创建一个新的事件循环并将其设置为当前循环。

由于此函数具有相当复杂的行为(特别是在使用了自定义事件循环策略的时候),更推荐在协程和回调中使用 get_running_loop() 函数而非 get_event_loop()

应该考虑使用 asyncio.run() 函数而非使用低层级函数来手动创建和关闭事件循环。

asyncio.set_event_loop(loop)

将 loop 设置为当前 OS 线程的当前事件循环。

asyncio.new_event_loop()

创建一个新的事件循环。

二、运行和停止

loop.run_until_complete(future)

运行直到 future ( Future 的实例 ) 被完成。

如果参数是 coroutine object ,将被隐式调度为 asyncio.Task 来运行。

返回 Future 的结果 或者引发相关异常。

loop.run_forever()

运行事件循环直到 stop() 被调用。

If stop() is called before run_forever() is called, the loop will poll the I/O selector once with a timeout of zero, run all callbacks scheduled in response to I/O events (and those that were already scheduled), and then exit.

If stop() is called while run_forever() is running, the loop will run the current batch of callbacks and then exit. Note that new callbacks scheduled by callbacks will not run in this case; instead, they will run the next time run_forever() or run_until_complete() is called.

loop.stop()

停止事件循环。

loop.is_running()

返回 True 如果事件循环当前正在运行。

loop.is_closed()

如果事件循环已经被关闭,返回 True 。

loop.close()

关闭事件循环。

当这个函数被调用的时候,循环必须处于非运行状态。pending状态的回调将被丢弃。

此方法清除所有的队列并立即关闭执行器,不会等待执行器完成。

这个方法是幂等的和不可逆的。事件循环关闭后,不应调用其他方法。

coroutine loop.shutdown_asyncgens()

Schedule all currently open asynchronous generator objects to close with an aclose() call. After calling this method, the event loop will issue a warning if a new asynchronous generator is iterated. This should be used to reliably finalize all scheduled asynchronous generators.

运行请注意,当使用 asyncio.run() 时,无需调用此函数。

实例代码

try:
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()

三、调度回调

loop.call_soon(callback*argscontext=None)

安排在下一次事件循环的迭代中使用 args 参数调用 callback 。

回调按其注册顺序被调用。每个回调仅被调用一次。

可选的仅关键字型参数 context 允许为要运行的 callback 指定一个自定义 contextvars.Context 。如果没有提供 context ,则使用当前上下文。

返回一个能用来取消回调的 asyncio.Handle 实例。

这个方法不是线程安全的。

loop.call_soon_threadsafe(callback*argscontext=None)

call_soon() 的线程安全变体。必须被用于安排 来自其他线程 的回调。

查看 并发和多线程 章节的文档。

注解

大多数 asyncio 的调度函数不让传递关键字参数。为此,请使用 functools.partial() :

# will schedule "print("Hello", flush=True)"
loop.call_soon(
    functools.partial(print, "Hello", flush=True))

使用 partial 对象通常比使用lambda更方便,asyncio 在调试和错误消息中能更好的呈现 partial 对象。

四、调度延迟回调

事件循环提供安排调度函数在将来某个时刻调用的机制。事件循环使用单调时钟来跟踪时间。

loop.call_later(delaycallback*argscontext=None)

安排 callback 在给定的 delay 秒(可以是 int 或者 float)后被调用。

返回一个 asyncio.TimerHandle 实例,该实例能用于取消回调。

callback 只被调用一次。如果两个回调被安排在同样的时间点,执行顺序未限定。

可选的位置参数 args 在被调用的时候传递给 callback  。 如果你想把关键字参数传递给 callback ,请使用 functools.partial() 。

可选的仅关键字型参数 context 允许为要运行的 callback 指定一个自定义 contextvars.Context 。如果没有提供 context ,则使用当前上下文。

loop.call_at(whencallback*argscontext=None)

安排 callback 在给定的绝对时间戳的 时间 (一个 int 或者 float)被调用,使用与 loop.time() 同样的时间参考。

这个函数的行为与 call_later() 相同。

返回一个 asyncio.TimerHandle 实例,该实例能用于取消回调。

在 3.7 版更改: 仅用于关键字形参的参数 context 已经被添加。请参阅: PEP 567 查看更多细节。

在 3.7.1 版更改: 在Python 3.7.0 和更早版本的默认事件循环实现中, when 与当前时间的差值不能超过一天。在 Python3.7.1中已被修复。

loop.time()

根据时间循环内部的单调时钟,返回当前时间, float 值。

五、创建 Futures 和 Tasks

loop.create_future()

创建一个附加到事件循环中的 asyncio.Future 对象。

这是在asyncio中创建Futures的首选方式。这让第三方事件循环可以提供Future 对象的替代实现(更好的性能或者功能)。

loop.create_task(coro)

安排一个 协程 的执行。返回一个 Task 对象。

三方的事件循环可以使用它们自己定义的 Task 类的子类来实现互操作性。这个例子里,返回值的类型是 Task 的子类。

loop.set_task_factory(factory)

设置一个 task 工厂 , 被用于 loop.create_task() 。

If factory is None the default task factory will be set. Otherwise, factory must be a callable with the signature matching (loop, coro), where loop is a reference to the active event loop, and coro is a coroutine object. The callable must return a asyncio.Future-compatible object.

loop.get_task_factory()

Return a task factory or None if the default one is in use.

六、在线程或者进程池中执行代码。

awaitable loop.run_in_executor(executorfunc*args)

安排在指定的执行器中调用 func 。

The executor argument should be an concurrent.futures.Executor instance. The default executor is used if executor is None.

import asyncio
import concurrent.futures

def blocking_io():
    # File operations (such as logging) can block the
    # event loop: run them in a thread pool.
    with open('/dev/urandom', 'rb') as f:
        return f.read(100)

def cpu_bound():
    # CPU-bound operations will block the event loop:
    # in general it is preferable to run them in a
    # process pool.
    return sum(i * i for i in range(10 ** 7))

async def main():
    loop = asyncio.get_running_loop()

    ## Options:

    # 1. Run in the default loop's executor:
    result = await loop.run_in_executor(
        None, blocking_io)
    print('default thread pool', result)

    # 2. Run in a custom thread pool:
    with concurrent.futures.ThreadPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, blocking_io)
        print('custom thread pool', result)

    # 3. Run in a custom process pool:
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, cpu_bound)
        print('custom process pool', result)

asyncio.run(main())

这个方法返回一个 asyncio.Future 对象。

使用 functools.partial() 传递关键字参数 给 func 。

七、事件循环实现

asyncio ships with two different event loop implementations: SelectorEventLoop and ProactorEventLoop.

By default asyncio is configured to use SelectorEventLoop on all platforms.

class asyncio.SelectorEventLoop

An event loop based on the selectors module.

Uses the most efficient selector available for the given platform. It is also possible to manually configure the exact selector implementation to be used:

import asyncio
import selectors

selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)

可用性: Unix, Windows。

八、其他

1、创建连接

coroutine loop.create_connection

(protocol_factoryhost=Noneport=None*ssl=Nonefamily=0proto=0flags=0sock=Nonelocal_addr=Noneserver_hostname=Nonessl_handshake_timeout=None)

Open a streaming transport connection to a given address specified by host and port.

coroutine loop.create_datagram_endpoint

(protocol_factorylocal_addr=Noneremote_addr=None*family=0proto=0flags=0reuse_address=Nonereuse_port=Noneallow_broadcast=Nonesock=None)

创建一个数据报连接。

oroutine loop.create_unix_connection(protocol_factorypath=None*ssl=Nonesock=Noneserver_hostname=Nonessl_handshake_timeout=None)

创建一个Unix套接字连接

2、创建网络服务

coroutine loop.create_server(protocol_factoryhost=Noneport=None*family=socket.AF_UNSPECflags=socket.AI_PASSIVEsock=Nonebacklog=100ssl=Nonereuse_address=Nonereuse_port=Nonessl_handshake_timeout=Nonestart_serving=True)

创建TCP服务 (socket 类型 SOCK_STREAM ) 监听 host 地址的 port 端口。

返回一个 Server 对象。

coroutine loop.create_unix_server(protocol_factorypath=None*sock=Nonebacklog=100ssl=Nonessl_handshake_timeout=Nonestart_serving=True)

Similar to loop.create_server() but works with the AF_UNIX socket family.

coroutine loop.connect_accepted_socket(protocol_factorysock*ssl=Nonessl_handshake_timeout=None)

Wrap an already accepted connection into a transport/protocol pair.

传输文件

TLS升级

监控文件描述符

使用scoket对象

DNS

使用管道

Unix信号

错误处理的handler自定义

运行子进程

回调处理

服务器对象(asyncio,提供给上层asyncio.open_connection、asyncio.start_server等调用

监控文件描述符的读事件

SIGINT和SIGTERM设置信号处理器

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
是的,asyncio使用事件循环(event loop)来驱动协程的执行。事件循环asyncio框架的核心部分,它负责管理协程的调度和执行。 事件循环会不断地从任务队列中取出待执行的协程,并调度它们的执行。当一个协程被挂起(使用`await`关键字),事件循环会暂停它的执行,并将控制权交给其他协程。一旦挂起的条件满足(例如等待IO完成或等待定时器触发),事件循环会继续执行挂起的协程。 在asyncio中,我们可以通过调用`asyncio.run()`函数来启动一个事件循环并运行程序。事件循环会一直运行,直到所有的协程任务都完成或被取消。 除了使用`asyncio.run()`函数启动事件循环外,我们还可以使用`asyncio.get_event_loop()`获取当前线程的事件循环对象,并调用它的`run_forever()`方法来手动运行事件循环。在这种模式下,我们可以通过调用`stop()`方法来停止事件循环的运行。 下面是一个简单示例: ```python import asyncio async def hello(): while True: print("Hello") await asyncio.sleep(1) async def main(): task = asyncio.create_task(hello()) await asyncio.sleep(5) task.cancel() asyncio.run(main()) ``` 上述代码定义了一个无限循环的协程函数`hello`,它每隔1秒打印"Hello"。在`main`函数中,我们使用`asyncio.create_task()`创建了一个任务,并等待5秒后取消它。 通过运行上述代码,你会发现协程`hello`会一直循环执行,直到被取消。这是因为事件循环会不断地调度协程的执行,使其始终保持循环状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值