Python线程池深度解析与学习方法

文章目录

  • 前言
  • 一、线程池的使用
  • 二、线程池的工作流程
  • 三、线程池的优势
  • 四、总结

  • 前言

           线程池是计算机编程中用于管理一组预先创建的线程的机制,这些线程可以被复用以执行多个任务。线程池的主要目的是提高程序的效率和响应性,通过减少线程创建和销毁的开销,以及合理分配线程资源来处理任务。


    一、线程池的使用

    在Python中,concurrent.futures模块提供了线程池的实现。ThreadPoolExecutor是该模块中用于创建线程池的类。以下是一个使用ThreadPoolExecutor创建线程池并执行任务的例子:

    from concurrent.futures import ThreadPoolExecutor
    
    # 创建一个包含5个线程的线程池
    pool = ThreadPoolExecutor(5)
    
    # 定义一个函数,该函数将被线程池中的线程执行
    def task_function(x):
        return x * x
    
    # 使用线程池执行任务
    results = [pool.submit(task_function, i) for i in range(10)]
    
    # 获取所有任务的结果
    for future in results:
        print(future.result())
    

    在这个例子中:

  • ThreadPoolExecutor(5)创建了一个包含5个线程的线程池。
  • task_function是一个简单的函数,它将输入值平方。
  • pool.submit(task_function,i)将任务提交给线程池,submit方法返回一个Future对象,可以用来获取任务的结果。
  • 通过future.result()获取每个任务的结果。
  • 再来个例子思考体会一下:

    import math
    import concurrent.futures
    
    
    def calculate_factorial(number):
        """计算一个数的阶乘"""
        return math.factorial(number)
    
    
    def main():
        numbers = [1, 2, 3, 4, 5]  # 任务列表,计算这些数的阶乘
    
        # 创建一个包含3个线程的线程池
        with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
            # 使用submit函数来提交任务
            futures = {executor.submit(calculate_factorial, number): number for number in numbers}
    
            # 获取并打印结果
            for future in concurrent.futures.as_completed(futures):
                number = futures[future]
                try:
                    result = future.result()
                except Exception as exc:
                    print(f"{number} generated an exception: {exc}")
                else:
                    print(f"The factorial of {number} is {result}")
    
    
    if __name__ == "__main__":
        main()
    

    The factorial of 2 is 2
    The factorial of 1 is 1
    The factorial of 3 is 6
    The factorial of 4 is 24
    The factorial of 5 is 120

    代码解析:

    1. 提交任务:使用executor.submit()方法将任务提交给线程池。submit()方法返回一个Future对象,该对象代表了正在执行的任务。我们使用字典futures来存储Future对象和对应的数字,以便在任务完成后可以找到原始的数字。
    2. 获取结果:使用concurrent.futures.as_completed()函数来迭代已完成的Future对象。当一个任务完成时,我们调用future.result()来获取任务的结果。如果任务执行过程中抛出了异常,result()方法会重新抛出这个异常,我们可以在try…except语句中捕获它。
    3. 处理异常:在try…except语句中,我们检查future.result()是否抛出异常。如果抛出异常,我们打印出异常信息;如果没有异常,我们打印出结果。

    使用map函数来提交任务并保持执行顺序

    import math
    import concurrent.futures
    
    
    def calculate_factorial(number):
        """计算一个数的阶乘"""
        return math.factorial(number)
    
    
    def main():
        numbers = [1, 2, 3, 4, 5]  # 任务列表,计算这些数的阶乘
    
        # 创建一个包含3个线程的线程池
        with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
            # 使用map函数来提交任务并保持执行顺序
            # 使用executor.map()方法将任务提交给线程池。与executor.submit()不同,map()方法会等待所有任务完成,并返回一个结果列表,保持了输入列表的顺序
            results = executor.map(calculate_factorial, numbers)
    
            # 打印结果
            for number, result in zip(numbers, results):
                print(f"The factorial of {number} is {result}")
    
    
    if __name__ == "__main__":
        main()
    

    The factorial of 1 is 1
    The factorial of 2 is 2
    The factorial of 3 is 6
    The factorial of 4 is 24
    The factorial of 5 is 120

    二、线程池的工作流程

  • 当线程数小于核心线程数时,每提交一个任务就创建一个线程来执行,即使当前有线程处于空闲状态,直到当前线程数达到核心线程数
  • 当前线程数达到核心线程数时,如果这个时候还提交任务,这些任务会被放到工作队列里,等到线程处理完了手头的任务后,会从队列中取任务处理。
  • 当前线程数达到核心线程数并且工作队列也满了,如果这个时候还提交任务,则会继续创建线程来处理,直到线程数达到最大线程数。
  • 当前线程数达到最大线程数并且队列也满了,如果这个时候还提交任务,则会触发饱和策略,如抛出异常或拒绝执行任务。
  • 三、线程池的优势

  • 资源消耗降低:通过重复利用已创建的线程,线程池可以降低线程创建和销毁造成的资源消耗。
  • 提高响应速度:当任务到达时,线程池中的线程可以立即执行任务,而无需等待新线程的创建。
  • 提高线程的可管理性:线程是稀缺资源,无限制的创建线程不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以进行统一分配、调优和监控。
  • 四、总结

    通过合理配置线程池的参数,如核心线程数、最大线程数、工作队列大小和饱和策略,可以有效地管理线程资源,提高程序的性能和稳定性。

    作者:想做个小Torvalds

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python线程池深度解析与学习方法

    发表回复