代码示例结合了多个Python编程概念和技术,包括装饰器、并发执行、异常处理和重试机制。

Image

代码

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 多线程 多进程
import functools
import time
from retrying import retry
import random

def timer(func):
    """装饰器,用于测量函数执行时间"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()  # 记录开始时间
        result = func(*args, **kwargs)  # 执行函数
        end_time = time.time()  # 记录结束时间
        print(f"{func.__name__} ran in {end_time - start_time:.4f} seconds")  # 打印运行时间
        return result
    return wrapper

@retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=3000)
def deal(x):
    time.sleep(2)
    number = random.randint(1, 10)
    if number % 3 == 0:
        print("发生错误", x)
        raise Exception(f"手动触发的错误")
    return x

@timer
def main():
    data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    with ThreadPoolExecutor() as executor:
        # 使用map函数将任务分配到各个线程中
        results = executor.map(deal, data)

        # 迭代结果
        for result in results:
            try:
                print(result)  # 这里会打印函数的返回值或者抛出异常
            except Exception as e:
                print(f"Error occurred: {e}")

if __name__ == '__main__':
    main()

知识点:

  1. 装饰器(Decorator):

    • timer 函数是一个装饰器,用于测量被装饰函数的执行时间。
    • 使用 functools.wraps 来保持原函数的名称和文档字符串。
    • 装饰器记录函数开始和结束的时间,并计算运行时长。
  2. 并发编程(Concurrency):

    • 使用 ThreadPoolExecutor 来创建一个线程池,用于并发执行任务。
    • executor.map 方法将 deal 函数应用于 data 列表中的每个元素。这些调用是并发执行的。
  3. 异常处理:

    • main 函数中的循环内部,使用 try-except 块来捕捉 deal 函数抛出的任何异常。
    • 如果在 deal 函数执行过程中发生异常,则打印一个错误消息。
  4. 重试机制(Retry Mechanism):

    • deal 函数使用 retry 装饰器,它会在函数抛出异常时自动重试。
    • 重试参数(最大尝试次数、重试等待的最小和最大时间)在装饰器中设定。
  5. 随机数生成:

    • deal 函数中使用 random.randint 生成一个随机整数。
    • 根据这个随机数的值来决定是否抛出异常。
  6. 休眠(Sleep):

    • deal 函数中使用 time.sleep 来模拟耗时操作。

这个代码示例是一个很好的实践,展示了如何在Python中结合使用装饰器、并发、异常处理和重试机制。这样的结构在处理需要同时管理时间效率和错误处理的复杂任务时非常有用。