Python使用asyncio异步时的常见问题总结

目录
  • 1. 如何停止任务?
  • 2. 如何等待任务完成?
  • 3. 如何从任务中获取返回值?
  • 4. 如何在后台运行任务?
  • 5. 如何等待所有后台任务?

1. 如何停止任务?

我们可以通过 asyncio.Task 对象上的 cancel() 方法取消任务。如果任务被取消,cancel() 方法返回 True,否则返回 False。

...
# cancel the task
was_cancelled = task.cancel()

如果任务已经完成,则无法取消,cancel() 方法将返回 False,任务不会处于已取消状态。

下次任务有机会运行时,它将引发 CancelledError 异常。如果 CancelledError 异常未在包装协程内处理,任务将被取消。

否则,如果在包装协程内处理了 CancelledError 异常,任务将不会被取消。cancel() 方法还可以接受一个消息参数,该参数将在 CancelledError 的内容中使用。

我们可以探索如何取消正在运行的任务。

在这个例子中,我们定义了一个任务协程,它报告一条消息然后阻塞片刻。

然后我们定义用作 asyncio 程序入口点的主协程。它报告一条消息,创建并安排任务,然后等待片刻。

然后主协程在运行时恢复和取消任务。它再等一会儿,让任务响应取消请求。然后主协程报告取消任务的请求是否成功。

任务被取消,然后完成。主协程然后在关闭程序之前报告任务的状态是否已取消。

# SuperFastPython.com
# example of canceling a running task
import asyncio

# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # block for a moment
    await asyncio.sleep(1)

# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine())
    # wait a moment
    await asyncio.sleep(0.1)
    # cancel the task
    was_cancelled = task.cancel()
    # report whether the cancel request was successful
    print(f'was canceled: {was_cancelled}')
    # wait a moment
    await asyncio.sleep(0.1)
    # check the status of the task
    print(f'canceled: {task.cancelled()}')
    # report a final message
    print('main coroutine done')

# start the asyncio program
asyncio.run(main())

运行该示例会启动 asyncio 事件循环并执行 main() 协程。main() 协程报告一条消息,然后创建并调度任务协程。然后它暂停并等待片刻以允许任务协程开始运行。任务运行,报告消息并休眠一段时间。

main() 协程恢复和取消任务。它报告取消任务的请求已成功。然后它会休眠片刻,让任务响应要取消的请求。

task_coroutine() 恢复并引发 CancelledError 异常,导致任务失败并完成。main()协程恢复并报告任务是否处于取消状态。在这种情况下,确实如此。

此示例突出显示了取消正在运行的任务的正常情况。

main coroutine started
executing the task
was canceled: True
canceled: True
main coroutine done

2. 如何等待任务完成?

我们可以通过直接等待 asyncio.Task 对象来等待任务完成。

...
# wait for the task to finish
await task

我们可以在一行中创建和等待任务。

...
# create and wait for the task to finish
await asyncio.create_task(custom_coro())

3. 如何从任务中获取返回值?

我们可能需要将协程的值返回给调用者。我们可以通过等待从协程中检索返回值。它假定正在等待的另一个协程返回一个值。

# coroutine that returns a value
async def other_coro():
	return 100

等待其他协程将挂起调用协程并安排其他协程执行。一旦另一个协程完成,调用协程将恢复。返回值将从另一个协程传递给调用者。

...
# execute coroutine and retrieve return value
value = await other_coro()

协程可以包装在 asyncio.Task 对象中。这有助于独立执行协程而无需当前协程等待它。

这可以使用 asyncio.create_task() 函数来实现。

...
# wrap coroutine in a task and schedule it for execution
task = asyncio.create_task(other_coro())

有两种方法可以从 asyncio.Task 中检索返回值,它们是:

  • 等待任务。
  • 调用结果() 方法。

我们可以等待任务来检索返回值。如果任务已安排或正在运行,则调用者将挂起,直到任务完成并提供返回值。如果任务完成,将立即提供返回值。

...
# get the return value from a task
value = await task

与协程不同,我们可以多次等待任务而不会引发错误。

...
# get the return value from a task
value = await task
# get the return value from a task
value = await task

我们还可以通过调用 asyncio.Task 对象的 result() 方法来获取任务的返回值。

...
# get the return value from a task
value = task.result()

这需要完成任务。如果不是,将引发 InvalidStateError 异常。如果任务被取消,将引发 CancelledError 异常。

4. 如何在后台运行任务?

我们可以通过将协程包装在 asyncio.Task 对象中来在后台运行协程。这可以通过调用 asyncio.create_task() 函数并将其传递给协程来实现。

协程将被包装在一个 Task 对象中,并被安排执行。将返回任务对象,调用者不会挂起。

...
# schedule the task for execution
task = asyncio.create_task(other_coroutine())

至少在当前协程出于任何原因挂起之前,任务不会开始执行。我们可以通过暂停片刻让任务开始运行来帮助解决问题。这可以通过休眠零秒来实现。

...
# suspend for a moment to allow the task to start running
await asyncio.sleep(0)

这将暂停调用者一小会儿,并允许请求运行的机会。这不是必需的,因为调用者可能会在未来某个时间暂停或作为正常执行的一部分终止。一旦调用者没有事情要做,我们也可以直接等待任务。

...
# wait for the task to complete
await task

5. 如何等待所有后台任务?

我们可以等待 asyncio 程序中的所有独立任务。这可以通过首先通过 asyncio.all_tasks() 函数获取一组所有当前正在运行的任务来实现。

...
# get a set of all running tasks
all_tasks = asyncio.all_tasks()

这将返回一个集合,其中包含一个 asyncio.Task 对象,用于当前正在运行的每个任务,包括 main() 协程。

我们不能直接等待这个集合,因为它会永远阻塞,因为它包含当前任务。因此,我们可以获取当前正在运行的任务的 asyncio.Task 对象并将其从集合中删除。

这可以通过首先调用 asyncio.current_task() 方法来获取当前协程的任务,然后通过 remove() 方法将其从集合中删除来实现。

...
# get the current tasks
current_task = asyncio.current_task()
# remove the current task from the list of all tasks
all_tasks.remove(current_task)

最后,我们可以等待剩余的任务集。这将挂起调用者,直到集合中的所有任务都完成。

...
# suspend until all tasks are completed
await asyncio.wait(all_tasks)

将它们结合在一起,下面添加到 main() 协程末尾的代码片段将等待所有后台任务完成。

...
# get a set of all running tasks
all_tasks = asyncio.all_tasks()
# get the current tasks
current_task = asyncio.current_task()
# remove the current task from the list of all tasks
all_tasks.remove(current_task)
# suspend until all tasks are completed
await asyncio.wait(all_tasks)

到此这篇关于Python使用asyncio异步时的常见问题总结的文章就介绍到这了,更多相关Python asyncio异步内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解python异步编程之asyncio(百万并发)

    前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥补了python性能方面的短板,如最新的微服务框架japronto,resquests per second可达百万级. python还有一个优势是库(第三方库)极为丰富,运用十分方便.asyncio是python3.4版本引入到标准库,python2x没有加这个库,毕竟python3x才是未来啊,哈哈!python3.5又加入了asyn

  • Python asyncio异步编程简单实现示例

    目录 一.asyncio事件循环简介 二.async协程函数简介 三.await关键字 四.async异步编程简单实现 今天继续给大家介绍Python相关知识,本文主要内容是Python asyncio异步编程简单实现. 一.asyncio事件循环简介 asyncio引入了事件循环的概念.事件循环是一个死循环,还循环会检测并执行某些代码.在Python中,引入了asyncio模块后,执行命令: loop=asyncio.get_event_loop() 可以生成一个事件循环,而执行命令: loo

  • 简单有效上手Python3异步asyncio问题

    目录 Python3异步asyncio问题 更新 下面是学习过程中记录的偏低层实现的资料 最基本的定义和应用 什么时候使用异步 并发和并行 异步结果回调 总结 Python3异步asyncio问题 官方文档: https://docs.python.org/zh-cn/3/library/asyncio-task.html#asyncio.run 看了一大堆相关的资料和教程,针对的Python版本不同,写法也各不一致,翻了翻官方的文档,发现其实越高版本的Python对异步进行封装的越方便,官方说

  • Python协程asyncio 异步编程笔记分享

    目录 1.事件循环 2.协程和异步编程 2.1 基本使用 2.2 await 2.3 Task对象 1.事件循环 可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑 #这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待 任务列表 = [ 任务1, 任务2, 任务3,... ] while True: 可执行

  • Python asyncio异步编程常见问题小结

    目录 一.asyncio编程简单示例 二.asyncio编程常见问题 三.报错原因及解决方案 今天继续给大家介绍Python相关知识,本文主要内容是Python asyncio异步编程常见问题. 一.asyncio编程简单示例 首先,我们来看一段简单的Python asyncio异步编程代码,相关代码如下所示: import asyncio async def fun(): print(1) await asyncio.sleep(2) print(2) return 3 async def m

  • Python使用asyncio异步时的常见问题总结

    目录 1. 如何停止任务? 2. 如何等待任务完成? 3. 如何从任务中获取返回值? 4. 如何在后台运行任务? 5. 如何等待所有后台任务? 1. 如何停止任务? 我们可以通过 asyncio.Task 对象上的 cancel() 方法取消任务.如果任务被取消,cancel() 方法返回 True,否则返回 False. ... # cancel the task was_cancelled = task.cancel() 如果任务已经完成,则无法取消,cancel() 方法将返回 False

  • python中asyncio异步编程学习

    1.   想学asyncio,得先了解协程 携程的意义: 计算型的操作,利用协程来回切换执行,没有任何意义,来回切换并保存状态 反倒会降低性能. IO型的操作,利用协程在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能,从而实现异步编程(不等待任务结束就可以去执行其他代码 2.协程和多线程之间的共同点和区别: 共同点: 都是并发操作,多线程同一时间点只能有一个线程在执行,协程同一时间点只能有一个任务在执行: 不同点: 多线程,是在I/O阻塞时通过切换线

  • Python协程asyncio异步编程笔记分享

    目录 1.事件循环 2.协程和异步编程 2.1基本使用 2.2await 2.3Task对象 1.事件循环 可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑 #这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待 任务列表 = [ 任务1, 任务2, 任务3,... ] while True: 可执行的任务

  • python 中的 asyncio 异步协程

    目录 一.定义协程 二.运行协程 三.协程回调 四.运行多个协程 五.run_forever 六.多协程中关闭run_forever 一.定义协程 asyncio 执行的任务,称为协程,但是Asyncio 并不能带来真正的并行 Python 的多线程因为 GIL(全局解释器锁)的存在,也不能带来真正的并行 import asyncio # 通过 async 定义一个协程 async def task(): print('这是一个协程') # 判断是否是一个协程,返回True print(asyn

  • Python使用asyncio包处理并发详解

    阻塞型I/O和GIL CPython 解释器本身就不是线程安全的,因此有全局解释器锁(GIL),一次只允许使用一个线程执行 Python 字节码.因此,一个 Python 进程通常不能同时使用多个 CPU 核心. 然而,标准库中所有执行阻塞型 I/O 操作的函数,在等待操作系统返回结果时都会释放GIL.这意味着在 Python 语言这个层次上可以使用多线程,而 I/O 密集型 Python 程序能从中受益:一个 Python 线程等待网络响应时,阻塞型 I/O 函数会释放 GIL,再运行一个线程

  • Python中asyncio模块的深入讲解

    1. 概述 Python中 asyncio 模块内置了对异步IO的支持,用于处理异步IO:是Python 3.4版本引入的标准库. asyncio 的编程模型就是一个消息循环.我们从 asyncio 块中直接获取一个 EventLoop 的引用,然后把需要执行的协程扔到 EventLoop 中执行,就实现了异步IO. 2. 用asyncio实现Hello world #!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Time : 2019/1/9

  • python 基于AioHttp 异步抓取火星图片

    翻译:大江狗 原文链接:https://pfertyk.me/2017/06/getting-mars-photos-from-nasa-using-aiohttp/ 小编注:aiohttp是基于asyncio实现的异步http框架. 本文案例也可以使用异步django实现. 我是Andy Weir写的<火星人>一书的忠实粉丝.阅读时,我想知道马克·沃特尼(Mark Watney)绕着红色星球走的感觉如何.最近,多亏了 Twilio的这篇博文, 我发现NASA提供了一个公共API,可以提供火星

随机推荐