深入探索Python协程:从基础到实践的学习笔记-01

文章目录

    • 取消任务和设置超时
      • 取消任务
      • 设置超时
    • future
    • 使用装饰器测量协程执行时间
    • 创建和操作事件循环

取消任务和设置超时

取消任务

要取消一个协程任务,你可以调用该任务的cancel()方法。这个操作会使得正在等待的asyncio.sleep()抛出asyncio.CancelledError异常。

import asyncioasync def my_coroutine():print("开始执行")try:await asyncio.sleep(5)except asyncio.CancelledError:print("任务被取消")finally:print("清理工作")async def main():task = asyncio.create_task(my_coroutine())await asyncio.sleep(2)  # 等待2秒task.cancel()  # 取消任务try:await taskexcept asyncio.CancelledError:print("任务已被取消")asyncio.run(main())

设置超时

要为协程设置超时,你可以使用asyncio.wait_for()函数。如果任务在指定的时间内没有完成,它将抛出asyncio.TimeoutError异常。

import asyncioasync def my_coroutine():print("开始执行")await asyncio.sleep(5)print("执行完成")async def main():try:await asyncio.wait_for(my_coroutine(), timeout=3)except asyncio.TimeoutError:print("任务超时")asyncio.run(main())

如果任务超时了,提示超时,但是不终止这个任务

#asyncio.shield的作用是保护一个协程免受取消操作的影响
import asyncioasync def my_coroutine():print("开始执行")await asyncio.sleep(5)print("执行完成")async def main():task = asyncio.create_task(my_coroutine())# 使用asyncio.wait_for来检测超时,但不取消任务try:await asyncio.wait_for(asyncio.shield(task), timeout=3)except asyncio.TimeoutError:print("任务超时,但仍在运行")# 等待任务真正完成await taskasyncio.run(main())

另外的方法

import asyncioasync def my_coroutine():print("开始执行")await asyncio.sleep(5)print("执行完成")async def main():# 创建任务,但不要等待它task = asyncio.ensure_future(my_coroutine())# 创建一个超时检测的协程async def timeout_detector(task):await asyncio.sleep(3)if not task.done():print("任务超时,但仍在运行")# 运行超时检测器asyncio.create_task(timeout_detector(task))# 等待任务完成await taskasyncio.run(main())

future

在Python中,Future 对象通常与并发编程相关,特别是在异步编程中。Future 代表了一个异步计算的结果,这个结果可能在将来的某个时间点可用。在Python的 asyncio 库中,Future 是一个核心概念,用于表示一个尚未完成的计算。

asyncio 中,通常会使用 asyncio.create_task() 函数或 asyncio.ensure_future() 函数来创建一个 Future 对象。

然而,从Python 3.7开始,asyncio.create_task() 成为了推荐的方式,因为它返回的是一个 Task 对象,这是 Future 的一个子类,提供了更多的功能。

下面是一个使用 asyncioFuture(通过 create_task())的简单示例:

import asyncioasync def fetch_data_from_web(url):# 模拟从网络获取数据的异步操作print(f"Starting fetch of {url}")await asyncio.sleep(1)  # 假设网络请求需要1秒return f"Data from {url}"async def main():# 创建一个任务(即 Future)task = asyncio.create_task(fetch_data_from_web("https://example.com"))# 在这里,我们可以做其他事情,而不需要等待fetch_data_from_web完成print("Doing other tasks...")await asyncio.sleep(0.5)  # 模拟其他任务需要0.5秒# 如果需要,我们可以等待任务完成并获取结果result = await taskprint(result)# 运行事件循环
asyncio.run(main())

在这个示例中,fetch_data_from_web 是一个模拟从网络获取数据的异步函数。在 main 函数中,我们使用 asyncio.create_task() 创建一个任务(即 Future),该任务将在后台执行 fetch_data_from_web 函数。然后,main 函数可以继续执行其他任务(在这个例子中,只是简单地打印一条消息并等待0.5秒)。当我们需要 fetch_data_from_web 的结果时,我们使用 await 关键字等待任务完成并获取结果。

注意:在Python中,通常使用 await 关键字与 FutureTask 对象交互,而不是直接操作它们。这是因为 FutureTask 是异步编程模型中的底层概念,而 await 提供了更高级、更直观的接口来与它们交互。

使用装饰器测量协程执行时间

在Python中,你可以使用装饰器来测量协程的执行时间。由于协程是异步执行的,你不能直接使用标准的time.time()函数来测量其执行时间,因为这会阻塞事件循环。相反,你需要使用异步上下文管理器(async with)和异步装饰器(async def)来包装协程,并在进入和退出上下文时记录时间。

以下是一个使用装饰器测量协程执行时间的示例:

import asyncio  
import time  
from typing import Callable, Awaitable  
from contextlib import asynccontextmanager  @asynccontextmanager  
async def measure_time(label: str):  start = time.time()  try:  yield  finally:  end = time.time()  print(f"{label} executed in {end - start:.2f} seconds")  def measure_coroutine(func: Callable[..., Awaitable[None]]) -> Callable[..., Awaitable[None]]:  async def wrapper(*args, **kwargs):  async with measure_time(f"Coroutine {func.__name__}"):  await func(*args, **kwargs)  return wrapper  # 示例协程  
async def example_coroutine():  print("Starting example coroutine...")  await asyncio.sleep(2)  # 模拟耗时操作  print("Finished example coroutine...")  # 应用装饰器  
example_coroutine = measure_coroutine(example_coroutine)  # 运行协程  
asyncio.run(example_coroutine())

然而,上面的示例虽然使用了装饰器,但实际上并没有真正地将measure_time作为装饰器直接应用于协程函数,因为装饰器本身不能是异步的。上面的代码实际上定义了一个异步上下文管理器measure_time,并使用了一个额外的包装函数wrapper来将measure_time上下文管理器应用到协程上。

如果你想要一个更“装饰器”风格的解决方案,并且不介意稍微改变一下用法,可以这样做:

import asyncio  
import time  
from typing import Callable, Awaitable  def measure_coroutine(func: Callable[..., Awaitable[None]]) -> Callable[..., Awaitable[None]]:  async def wrapper(*args, **kwargs):  start = time.time()  await func(*args, **kwargs)  end = time.time()  print(f"Coroutine {func.__name__} executed in {end - start:.2f} seconds")  return wrapper  # 示例协程  
@measure_coroutine  
async def example_coroutine():  print("Starting example coroutine...")  await asyncio.sleep(2)  # 模拟耗时操作  print("Finished example coroutine...")  # 运行协程  
asyncio.run(example_coroutine())

在这个版本中,装饰器measure_coroutine直接返回一个新的协程函数wrapper,它测量了原始协程的执行时间并打印出来。这样可以直接在协程函数上使用装饰器,而不需要额外的包装或调用。

创建和操作事件循环

在Python中,使用asyncio库实现协程时,可以手动创建和访问事件循环。以下是一个简单的代码示例,展示了如何手动创建和操作事件循环:

import asyncio
async def my_coroutine():print("协程开始执行")await asyncio.sleep(1)print("协程执行完毕")
def main():# 手动创建事件循环loop = asyncio.get_event_loop()# 创建协程任务coroutine = my_coroutine()task = loop.create_task(coroutine)# 启动事件循环try:loop.run_until_complete(task)finally:# 关闭事件循环loop.close()
if __name__ == "__main__":main()

在这个示例中,我们首先导入了asyncio库,然后定义了一个协程my_coroutine。在main函数中,我们手动创建了一个事件循环,将协程封装为一个任务,然后启动事件循环。当任务完成时,事件循环会关闭。

需要关注的问题:

  1. 事件循环的创建和关闭:确保在程序开始时创建事件循环,并在结束时关闭它。在上述代码中,我们使用asyncio.get_event_loop()来获取当前事件循环,或者创建一个新的。使用loop.close()来关闭事件循环。
  2. 事件循环的唯一性:通常情况下,一个程序中只会有一个活动的事件循环。在多线程应用程序中,每个线程都有自己的事件循环。
  3. 异步编程模型:使用asyncawait关键字来定义协程,并使用asyncio库提供的函数来操作它们。这有助于保持代码的异步性和非阻塞性。
  4. 任务的取消和异常处理:在异步编程中,任务可能会被取消,也可能会抛出异常。确保使用tryexcept块来处理这些情况,以保持程序的稳定性。
  5. 资源泄漏:在协程中使用的资源(如文件、网络连接等)应该在协程完成后正确释放,以避免资源泄漏。
  6. 并发和并行asyncio库提供了并发执行的机制,但它通常是单线程的。如果需要真正的并行执行,可以考虑使用concurrent.futures模块或asynciorun_in_executor方法。
  7. 与线程和进程的交互:在异步编程中,可能会需要与线程或进程交互。asyncio库提供了asyncio.run_in_executor方法来在另一个线程或进程中运行阻塞代码。
  8. 性能和调试:异步编程模型可能会带来性能优势,但也可能使调试变得更加复杂。使用适当的工具和日志记录来帮助调试异步代码。
    通过关注这些问题,你可以更有效地使用Python中的asyncio库来编写和维护异步代码。

备注:

在Python 3.10及更高版本中,asyncio.get_event_loop()已被弃用,因为它可能会导致线程安全问题。如果你的代码中出现了DeprecationWarning: There is no current event loop警告,这意味着你在尝试获取事件循环时,当前线程中没有设置的事件循环。

为了解决这个问题,你应该使用asyncio.run()函数来运行你的异步程序,它会自动创建和设置一个新的事件循环,并在结束时关闭它。这是Python 3.7引入的新方法,用于简化异步程序的启动和运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/11189.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回溯之组合总和II

上一篇文章使用回溯解决了组合总和I,这次使用回溯解决组合总和II,下面先给出回溯的模板代码。 private void backtracking(参数1,参数2,...){if(递归终止条件){收集结果;return;}for(遍历集合){处理;backtracking(参数1,参数2,...); // 递归;回溯;} }组…

5. FactoryTalk View SE -- 模拟量趋势记录

step1: 在项目列表下找到数据记录–数据记录模型–新建。 step2:更改描述、文件标识符、存储格式。 step3:更改文件缓存路径。 step4:更改缓存文件保存的周期。 step5:5s保存一次数据。 step6:添加标…

zero123 转 diffusers 的 base model

zero123 转 diffusers 的 base model Q1Q2 Q1 ModuleNotFoundError: No module named pipeline_zero1to3将pipeline_zero1to3.py放到convert_zero123_to_diffusers.py同级目录下 pip install kornia pip install pytorch_lightningQ2 $ python ./diffusers/scripts/convert…

从零开始搭建Springboot项目脚手架2:配置文件、返回值、日志等

1、多个环境与配置文件 2、统一返回值 返回值包括两种场景:正常controller的返回、异常发生之后返回 正常controller的返回:通过在controller的默认返回Response实现 异常发生之后返回:通过全局异常处理统一捕获返回 首先创建类StatusCode…

Java中的NIO及其与传统IO的区别

Java的NIO(New Input/Output)是从Java 1.4版本开始引入的一套新的IO API,用来替代标准Java IO API。NIO支持面向缓冲区的(Buffer-oriented)、基于通道的(Channel-based)IO操作。NIO旨在提高IO操…

[Spring Cloud] (7)gateway防重放拦截器

文章目录 简述本文涉及代码已开源Fir Cloud 完整项目防重放防重放必要性:防重放机制作用: 整体效果后端进行处理 后端增加防重放开关配置签名密钥 工具类防重放拦截器 前端被防重放拦截增加防重放开关配置请求头增加防重放签名处理防重放验证处理函数bas…

打造清洁宜居家园保护自然生态环境,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境,作为我们人类赖以生存的家园,其健康与否直接关系到我们的生活质量。然而,近年来,一些不法分子为了个人私利,在河边、路边等公共区域肆意倾倒垃圾,严重破坏了环境的健康与平衡。这种行为不仅损…

ffmpeg推流flv到rtmp

前言 使用ffmpeg推流很简单,使用ffmpeg命令推流更简单。本篇以本文标题《ffmpeg推流flv到rtmp》为中心。只推流输入flv格式的媒体文件,只推流到rtmp。 原因很简单,简化一切复杂的流程,稍后再说原因。我们通过多篇慢慢的提升代码复杂度,例如:把mp4推流到rtmp需要使用ffm…

18.04版本的ubuntu没有连接网络的图标(坑人版)

以下更新内核别看,因为后面安装驱动报一堆错误!!! 不升级内核成功方法跳转连接:https://blog.csdn.net/weixin_53765004/article/details/138771613?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2213877…

单调栈问题

原理 单调栈的核心原理是:在栈内保持元素的单调性(递增或递减) 单调递增栈: 用于处理“下一个更小的元素”问题。当新元素比栈顶元素小或等于时,直接入栈;否则,一直从栈顶弹出元素&#xff0c…

React 第二十六章 React.memo

React.memo 是 React 提供的一个高阶组件&#xff0c;用于对函数组件进行性能优化。 React.memo 的源码实际上就是返回一个 PureComponent 组件&#xff1a; function memo(FuncComp){return class Memo extends PureComponent{render(){return <>{FuncComp(this.props…

OBS直播二次开发_OBS直播软件介绍

OBS工作室版 免费且开源的用于视频录制以及直播串流的软件。 下载以在Windows, Mac以及Linux上简单且快速的开始串流。 功能 实时高性能的视频/音频捕捉与混合,以及无限的场景模式使您可以通过自定义实现无缝转换。为视频源设计的滤镜例如图片蒙版,色彩校正,色度/色彩键控…

软件体系结构风格

目录 一、定义 二、.经典软件体系结构风格&#xff1a; 1.管道和过滤器 2.数据抽象和面向对象系统 3.基于事件系统&#xff08;隐式调用&#xff09; 4.分层系统 5.仓库 6.C2风格 7.C/S 8.三层C/S 9.B/S 题&#xff1a; 一、定义 软件体系机构风格是描述某一特定应用…

没想到 JSON 还可以像 XPATH 方式进行操作,简直不要太爽

Jayway JsonPath 是一种 Java 库&#xff0c;用于在 Java 应用程序中解析和操作 JSON 数据。它提供了一种便捷的方式来定位和提取 JSON 文档中的信息&#xff0c;通过使用类似于 XPath 的语法&#xff0c;开发人员能够轻松地选择和操作 JSON 数据。 JsonPath 表达式是由用点分…

物联网系统

文章目录 一、物联网二、物联网系统1.核心特点2.体系构架3.作用 一、物联网 物联网&#xff08;Internet of Things&#xff0c;IoT&#xff09;是指将各种物理设备&#xff08;如传感器、执行器、嵌入式系统等&#xff09;通过互联网连接起来&#xff0c;并通过云计算系统实现…

通过内网穿透实现远程访问个人电脑资源详细过程(免费)(NatApp + Tomcat)

目录 1. 什么是内网穿透 2. 内网穿透软件 3. NatApp配置 4. 启动NatApp 5. 通过内网穿透免费部署我们的springboot项目 通过内网穿透可以实现远程通过网络访问电脑的资源&#xff0c;本文主要讲述通过内网穿透实现远程访问个人电脑静态资源的访问&#xff0c;下一章节将讲…

C语言/数据解构——(随即链表的复制)

一.前言 嗨嗨嗨&#xff0c;大家好久不见。已经有好几天没更新了。今天我们就分享一道链表题吧——随即链表的复制https://leetcode.cn/problems/copy-list-with-random-pointer废话不多说&#xff0c;让我们直接开始今天的题目分享吧。 二.正文 1.1题目描述 他和单链表不同…

超级好用的C++实用库之点阵字体

&#x1f4a1; 需要该C实用库源码的大佬们&#xff0c;可搜索微信公众号“希望睿智”。添加关注后&#xff0c;输入消息“超级好用的C实用库”&#xff0c;即可获得源码的下载链接。 概述 点阵字体是一种数字字体&#xff0c;其中每个字符都由一定尺寸的像素矩阵组成。比如&…

华为OD机试 - 求幸存数之和(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

机器学习面试篇

如何理解机器学习数据集的概念 数据集是机器学习的基础&#xff0c;它包括了用于训练和测试模型所需的数据。数据集通常以矩阵的形式存在&#xff0c;其中每一行代表一个样本&#xff08;或实例&#xff09;&#xff0c;每一列代表一个特征&#xff08;或属性&#xff09;。…