Python的线程池 (Thread Pool)

185 阅读3分钟

线程池是一种管理多个线程的机制,可以复用线程,避免频繁地创建和销毁线程,从而提升程序的性能。Python 提供了 concurrent.futures 模块中的 ThreadPoolExecutor 类来实现线程池。

优点

  • 线程复用:可以重复使用线程,避免频繁的线程创建和销毁。
  • 管理简便:线程池可以自动管理线程的生命周期(创建、执行、销毁)。
  • 提高性能:对于大量短时间的任务,线程池可以提高并发性能。

适用场景:线程池特别适用于处理大量短任务,尤其是 I/O 密集型任务(如文件读写、网络请求等)。

使用 ThreadPoolExecutor 创建线程池

ThreadPoolExecutor 主要提供了 submit()map() 两个方法,前者提交一个任务,后者将一组任务传递给线程池进行并发执行。

示例代码

下面是一个使用线程池的简单例子,模拟多个任务并发执行:


复制编辑
import time
from concurrent.futures import ThreadPoolExecutor

# 模拟一个任务
def task(n):
    print(f"任务 {n} 开始执行")
    time.sleep(2)  # 模拟耗时操作
    print(f"任务 {n} 执行完毕")
    return f"结果 {n}"

def main():
    # 创建一个线程池,最大线程数为 3
    with ThreadPoolExecutor(max_workers=3) as executor:
        # 使用 submit 提交任务
        futures = [executor.submit(task, i) for i in range(5)]
        
        # 获取结果
        for future in futures:
            result = future.result()  # 阻塞直到任务执行完毕
            print(f"获取到结果: {result}")

if __name__ == "__main__":
    main()

代码解析

  1. 创建线程池

    • 使用 ThreadPoolExecutor(max_workers=3) 创建一个线程池,最多同时运行 3 个线程。
    • max_workers 参数决定了线程池中线程的最大数量。
  2. 提交任务

    • 使用 executor.submit(task, i) 提交任务,每个任务返回一个 Future 对象。submit 方法会异步执行任务,并立即返回 Future 对象。
    • futures 列表保存了所有任务的 Future 对象。
  3. 获取任务结果

    • 使用 future.result() 获取任务的执行结果。如果任务还没有完成,result() 会阻塞直到任务完成并返回结果。
  4. 自动关闭线程池

    • 使用 with ThreadPoolExecutor(...) 语句,线程池会在 with 块结束后自动关闭,不需要显式调用 executor.shutdown()

线程池的优势

  • 线程池可以有效避免创建线程的开销,复用线程资源。
  • 可以设置线程池的最大线程数,控制并发的线程数量,避免线程过多导致资源竞争。

使用 map() 方法执行多个任务

ThreadPoolExecutor 还提供了 map() 方法,它会阻塞并返回任务的执行结果,类似于 map() 函数。该方法适合于同时运行多个任务,并且需要等待所有任务完成后再返回结果。


复制编辑
import time
from concurrent.futures import ThreadPoolExecutor

def task(n):
    print(f"任务 {n} 开始执行")
    time.sleep(2)
    print(f"任务 {n} 执行完毕")
    return f"结果 {n}"

def main():
    with ThreadPoolExecutor(max_workers=3) as executor:
        # 使用 map 同时执行多个任务
        results = executor.map(task, range(5))
        
        # 输出结果
        for result in results:
            print(f"获取到结果: {result}")

if __name__ == "__main__":
    main()

总结

  • submit() :适用于需要并行执行多个任务,并且可以异步处理每个任务的情况。需要手动获取结果。
  • map() :适用于处理一组任务并等待所有任务完成的情况。该方法会返回任务的执行结果。