线程池是一种管理多个线程的机制,可以复用线程,避免频繁地创建和销毁线程,从而提升程序的性能。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()
代码解析:
-
创建线程池:
- 使用
ThreadPoolExecutor(max_workers=3)创建一个线程池,最多同时运行 3 个线程。 max_workers参数决定了线程池中线程的最大数量。
- 使用
-
提交任务:
- 使用
executor.submit(task, i)提交任务,每个任务返回一个Future对象。submit方法会异步执行任务,并立即返回Future对象。 futures列表保存了所有任务的Future对象。
- 使用
-
获取任务结果:
- 使用
future.result()获取任务的执行结果。如果任务还没有完成,result()会阻塞直到任务完成并返回结果。
- 使用
-
自动关闭线程池:
- 使用
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():适用于处理一组任务并等待所有任务完成的情况。该方法会返回任务的执行结果。