Administrator
Published on 2025-03-14 / 4 Visits
0
0

用 Python 装饰器记录同步和异步函数执行时间

以下是一个能够记录同步和异步函数执行时间的装饰器实现:

import time
import functools
from inspect import iscoroutinefunction

def record_time(func):
    """记录函数执行时间的装饰器,支持同步和异步函数"""

    # 处理同步函数
    @functools.wraps(func)
    def sync_wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start_time
        print(f"[同步] 函数 {func.__name__} 执行时间: {elapsed:.4f}秒")
        return result

    # 处理异步函数
    @functools.wraps(func)
    async def async_wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = await func(*args, **kwargs)
        elapsed = time.perf_counter() - start_time
        print(f"[异步] 函数 {func.__name__} 执行时间: {elapsed:.4f}秒")
        return result

    # 根据函数类型返回对应的包装器
    return async_wrapper if iscoroutinefunction(func) else sync_wrapper

使用示例:

# 测试同步函数
@record_time
def sync_task():
    time.sleep(1)
    return "同步任务完成"

# 测试异步函数
@record_time
async def async_task():
    await asyncio.sleep(1)
    return "异步任务完成"

# 运行测试
if __name__ == "__main__":
    # 测试同步函数
    print(sync_task())

    # 测试异步函数
    import asyncio
    print(asyncio.run(async_task()))

实现说明:

  1. 使用time.perf_counter()获取高精度时间戳,比time.time()更适合性能测量
  2. 通过inspect.iscoroutinefunction判断被装饰函数是否是异步函数
  3. 使用functools.wraps保留原始函数的元信息
  4. 同步版本直接执行函数并计算耗时
  5. 异步版本使用await执行并计算耗时
  6. 输出信息中标注了函数类型便于区分

输出示例:

[同步] 函数 sync_task 执行时间: 1.0012秒
同步任务完成
[异步] 函数 async_task 执行时间: 1.0015秒
异步任务完成

该装饰器特点:

  • 自动识别同步/异步函数
  • 保持函数返回值不变
  • 使用高精度计时器
  • 保留原始函数元信息
  • 输出信息包含函数类型标识
  • 同时支持带参数和不带参数的函数
  • 兼容各种Python 3.5+的协程语法

Comment