官网连接: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设置信号处理器