pythonasyncio在哪个版本好_总结python3.8版本中asyncio的常用模块及使用方法(一. 协程和任务)...

刷了一遍3.8文档中asyncio的部分, 总结一些基本的知识点, python后续版本中, 这个模块更新目测也会比较频繁, 虽然到3.6为止, 这个模块还不是很好用, 但从目前来看, python最新版本更新的asycnio模块已经越来越趋于稳定了.

3.8版本中有一部分的api已经宣布不推荐使用, 并会在python3.10版本中弃用, 本文章中已过滤掉将会弃用的函数,并在文章最后简要概括.

本文内容基于python3.8官方文档编写, 很多内容与python3.8官方文档相同, 英语较好的童鞋请直接阅读官方文档:

ok~ 开始扯皮~

先解释一下高级函数和低级函数:

越高级的函数封装的越完整, 越有可能被用户使用.

越低级的函数, 则越接触底层, 越有可能用户基本用不到.

1.1 协程

使用async/await语法声明的协程是编写异步应用程序的首选. 例如, 以下代码段(需要python3.7+)打印"hello", 等待1秒钟, 然后打印"hello"

>>> import asyncio

>>> async def main():...

print('hello')...

await asyncio.sleep(1)...

print('world')

>>> asyncio.run(main())

hello

world

复制代码

请注意,仅调用协程不会调度它的执行:

>>> main()

为了实际运行协程,asyncio提供了三种主要机制:

使用asyncio.run()函数来运行顶层入口函数"main"(请参照上面的例子)

等待协程. 下面的代码片段将在等待1秒钟后显示“ hello”,然后在等待另外 2秒钟后显示“ world” :

import asyncio

import time

async def say_after(delay, what):

await asyncio.sleep(delay)

print(what)

async def main():

print(f"started at {time.strftime('%X')}")

await say_after(1, 'hello')

await say_after(2, 'world')

print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

复制代码

预期的输出:

started at 17:13:52

hello world

finished at 17:13:55

复制代码asyncio.create_task() 以异步任务的形式并发运行协程

让我们修改上面的例子,并发地运行两个say_after协程:

async def main():

task1 = asyncio.create_task(say_after(1, 'hello'))

task2 = asyncio.create_task(say_after(2, 'world'))

print(f"started at {time.strftime('%X')}") # 等待,直到两个任务都完成(应该花费大概2秒钟)

await task1

await task2

print(f"finished at {time.strftime('%X')}")

复制代码

注意,预期的输出现在显示代码段比以前快了1秒:

started at 17:14:32

hello world

finished at 17:14:34

复制代码

注: 协程的基本写法, 需要通过asyncio.create_task来将异步函数封装成任务, 然后通过asyncio.run来执行协程函数

1.2 异步

如果一个对象可以用在一个await表达式中,我们就说它是一个awaitable对象。许多异步api被设计成awaitable对象。

有三种主要类型的可访问对象:协程、任务和结果。

协程(conoutines):

Python协程是可等待的,因此可以从其他协程等待:

import asyncioasync def nested(): return 42async def main():

# 如果只调用“nested()”,则什么也不会发生。

# 一个协程对象被创建,但不是等待,

# 所以它根本不会运行。

nested() # 让我们现在换一种方式来等待他的执行:

print(await nested()) # 将会输出 "42".asyncio.run(main())

复制代码

这里有一个很重要的概念是,术语“协程”与两个概念密切相关:

协程函数:异步def函数;

协程对象:通过调用协同程序函数返回的对象。

异步还支持基于生成器的协同程序。

任务(task):

任务用于并发地调度协程。

当协程被包装到一个任务中,并带有asyncio.create_task()这样的函数时,协程会被自动调度且很快运行:

import asyncio

async def nested():

return 42

async def main(): # 在 "main()" 中调用nested()以尽快并发执行

task = asyncio.create_task(nested()) # "task" 现在可以被用来取消 "nested()" 或者可以简单地等待直到它完成:

await task

asyncio.run(main())

复制代码

结果(future):

Future是一个特殊的低级可访问对象,它表示异步操作的最终结果。

当一个Future对象被等待时,这意味着协程将等待,直到将来在其他地方被解析。

异步中的Future对象需要允许基于回调的代码与异步/等待一起使用。

通常不需要在应用程序级代码中创建Future的对象。

Future对象,有时通过库和一些asyncio的api暴露,是可以等待的对象:

async def main():

await function_that_returns_a_future_object()

# 这也是有效的:

await asyncio.gather(function_that_returns_a_future_object(),

some_python_coroutine())

复制代码

loop.run_in_executor()

是返回Future对象的低级函数的一个好例子。

注: 1. 一个异步函数只有被封装成awaitable或任务的形式才会被真正的执行

2. 建议将简单的逻辑通过await函数封装, 复杂的函数通过create_task函数封装

简单示例如下:

import asyncio

async def main():

result_await = await function_data("t1") # 会一直阻塞到函数结束

result_create_task = asyncio.create_task(function_data("t2")) # 继续, 可以通过下边方式或其他方式检测任务状态

while not result_create_task.done():

print("waiting")

await asyncio.sleep(1)

else:

print(result_create_task.done())

print(result_create_task.result())

asyncio.run(main())

复制代码

1.3 运行异步程序:

asyncio.run(coro, *, debug=False)

执行协程 coro并返回结果。

这个函数运行传递过来的协程参数,负责管理异步事件循环并完成异步生成器。

当另一个异步事件循环在同一线程中运行时,不能调用此函数。

如果debug设置为True,则事件循环将在调试模式下运行。

这个函数总是创建一个新的事件循环并在结束时关闭它。它应该用作异步程序的主要入口点,并且在理想情况下应该只调用一次。

示例:

async def main():

await asyncio.sleep(1)

print('hello')

asyncio.run(main())

复制代码

注: 这个函数是3.7新增加的函数, 建议作为异步程序的唯一主入口函数

1.4 创建任务

asyncio.create_task(coro, *, name=None)

将协程参数coro封装到任务中,并安排其执行。返回任务对象。

如果name不是None,则使用task .set_name()将其设置为任务的名称。

任务在get_running_loop()返回的loop中执行,如果当前线程中没有运行loop,则会引发RuntimeError。

这个函数是在Python 3.7中添加的。在Python 3.7之前,可以使用低级别的asyncio.ensure_future()函数:

在版本3.8中, 新增名称参数

async def coro(): ...# In Python 3.7+

task = asyncio.create_task(coro())... # 这适用于所有Python版本,但可读性较差

task = asyncio.ensure_future(coro())

复制代码

注: 这个函数也是3.7新增加的函数, 可以将异步函数作为参数放入此函数中封装成任务, 并通过上边的run函数来执行任务

1.5 从其他线程调度

asyncio.run_coroutine_threadsafe(coro, loop)

将协程提交给给定的事件loop。该函数是线程安全的。

返回一个concurrent.futures.Future 去接收另一个OS线程的结果。

这个函数应该从不同的OS线程调用,而不是在事件循环运行的线程中调用。

示例:

# 创建一个协程

coro = asyncio.sleep(1, result=3)

# 将协程提交给给定的loop

future = asyncio.run_coroutine_threadsafe(coro, loop)

# 等待带有可选超时参数的结果

assert future.result(timeout) == 3

复制代码

如果在协程中引发异常,将通知返回的Future。也可以用来取消事件循环中的任务:

try:

result = future.result(timeout)

except asyncio.TimeoutError:

print('协程花了太长时间,取消了任务…')

future.cancel()

except Exception as exc:

print(f'协程引发了一个异常: {exc!r}')

else:

print(f'返回的协程: {result!r}')

复制代码

与其他异步函数不同,此函数需要显式传递loop参数。

注: 可以通过该函数做到不同线程间的任务调度

1.6 自省

asyncio.current_task(loop=None)

返回当前正在运行的任务实例,如果没有任务正在运行,则返回None。

如果loop为空,则使用get_running_loop()获取当前循环。

注: python3.7中新增的api, 是非常实用的函数

asyncio.all_tasks(loop=None)¶

返回一组由loop运行的尚未完成的任务对象。

如果loop为None,则使用get_running_loop()获取当前的loop。

注: python3.7中新增的api, 是非常实用的函数

emmmm, 第一部分的主要内容就是如上了, 上述模块也是asyncio目前最新版本中最核心的功能api, 请牢记用法.

现在记录一下目前还存在, 但是预计在python3.10中删掉的api:

1. 睡眠

asyncio.sleep(delay, result=None, *, loop=None)

用来挂起当前任务, 等待其他任务

2. 并发运行的任务

asyncio.gather(*aws, loop=None, return_exceptions=False)¶

在aws中并发运行可异步的对象

3. 屏蔽取消

asyncio.shield(aw, *, loop=None)

保护一个可被取消的对象。

4. 超时

asyncio.wait_for(aw, timeout, *, loop=None)¶

等待一个可异步的程序完成并设置超时

5. 等待

asyncio.wait(aws, *, loop=None, timeout=None, return_when=ALL_COMPLETED)¶

并发地运行aws中的可异步对象,并阻塞该对象,直到返回指定的条件为止。

asyncio.as_completed(aws, *, loop=None, timeout=None)

并发地运行aws集合中的可访问对象。返回Future对象的迭代器。返回的每个Future对象中表示剩余等待对象集合的最早结果。

6. task对象

class asyncio.Task(coro, *, loop=None, name=None)

运行Python协程的类似Future的对象。不是线程安全的。

7. 基于协程的生成器

基于生成器的协程先于异步/等待语法。它们是Python生成器,使用表达式的方式来等待Future和其他协程。

如果本篇内容能够帮助到您, 希望点个关注, 共同成长~

pythonasyncio在哪个版本好_总结python3.8版本中asyncio的常用模块及使用方法(一. 协程和任务)..._第1张图片

你可能感兴趣的:(pythonasyncio在哪个版本好_总结python3.8版本中asyncio的常用模块及使用方法(一. 协程和任务)...)