python线程池(concurrent.futuresl)模块
转自:https://www.jianshu.com/p/b9b3d66aa0be
Python
中已经有了threading
模块,为什么还需要线程池呢,线程池又是什么东西呢?在介绍线程同步的信号量机制的时候,举得例子是爬虫的例子,需要控制同时爬取的线程数,例子中创建了20个线程,而同时只允许3个线程在运行,但是20个线程都需要创建和销毁,线程的创建是需要消耗系统资源的,有没有更好的方案呢?其实只需要三个线程就行了,每个线程各分配一个任务,剩下的任务排队等待,当某个线程完成了任务的时候,排队任务就可以安排给这个线程继续执行。
这就是线程池的思想(当然没这么简单),但是自己编写线程池很难写的比较完美,还需要考虑复杂情况下的线程同步,很容易发生死锁。从Python3.2
开始,标准库为我们提供了concurrent.futures
模块,它提供了ThreadPoolExecutor
和ProcessPoolExecutor
两个类,实现了对threading
和multiprocessing
的进一步抽象(这里主要关注线程池),不仅可以帮我们自动调度线程,还可以做到:
- 主线程可以获取某一个线程(或者任务的)的状态,以及返回值。
- 当一个线程完成的时候,主线程能够立即知道。
- 让多线程和多进程的编码接口一致。
实例
简单使用
1 from concurrent.futures import ThreadPoolExecutor 2 import time 3 import os 4 5 def copy_file(old_folder_name, new_folder_name): 6 file_names = os.listdir(old_folder_name) 7 for file_name in file_names: 8 print("已拷贝文件:%s" % (new_folder_name+'/'+file_name)) 9 return 3 10 11 12 executor = ThreadPoolExecutor(max_workers=3) 13 # 通过submit函数提交执行的函数到线程中,submit函数立即返回,不堵塞 14 old_folder_name = 'test1' 15 new_folder_name = 'test1[复件]' 16 task = executor.submit(copy_file, old_folder_name, new_folder_name) 17 # done方法用于判断某个人物是否完成 18 print(task.done()) 19 # cancel方法用于取消某个任务,该任务没有放入线程池中才能取消成功 20 print(task.cancel()) 21 time.sleep(4) 22 print(task.done()) 23 # result方法可以获取task的执行结果 24 print(task.result())
运行结果:
False False 已拷贝文件:test1[复件]/_compat_pickle.py 已拷贝文件:test1[复件]/_compression.py 已拷贝文件:test1[复件]/_dummy_thread.py 已拷贝文件:test1[复件]/_markupbase.py 已拷贝文件:test1[复件]/_osx_support.py 已拷贝文件:test1[复件]/_pydecimal.py 已拷贝文件:test1[复件]/_pyio.py 已拷贝文件:test1[复件]/_py_abc.py True 3