对于任务数量比较多,而且不断增加的程序,每一个任务生成一个线程,这样频繁的操作,会让线程数量失控,同时有些线程的生成和销毁都需要cpu和数据资源,另外,线程死锁也是很大问题,为了更好的管理线程,于是开发了线程池模块。例如:爬虫程序遇到的问题。python中的threadpool模块,逐步被python3中的标准库concurrent.futures模块提供的ThreadPoolExecutor和ProcessPoolExecutor两个类替代。这两个类对threading和multiprocessing做了进一步封装和抽象。 一、ThreadPoolExecutor 1、submit方法: 这个类提供了submit来提交一个线程给线程池。
from concurrent.futures import ThreadPoolExecutor import time # 参数times用来模拟网络请求的时间 def get_html(times): time.sleep(times) print("get page {}s finished".format(times)) return times executor = ThreadPoolExecutor(max_workers=2) # 通过submit函数提交执行的函数到线程池中,submit函数立即返回,不阻塞 task1 = executor.submit(get_html, (3)) task2 = executor.submit(get_html, (2)) # done方法用于判定某个任务是否完成 print(task1.done()) # cancel方法用于取消某个任务,该任务没有放入线程池中才能取消成功 print(task2.cancel()) time.sleep(4) print(task1.done()) # result方法可以获取task的执行结果 print(task1.result()) # 执行结果 # False # 表明task1未执行完成 # False # 表明task2取消失败,因为已经放入了线程池中 # get page 2s finished # get page 3s finished # True # 由于在get page 3s finished之后才打印,所以此时task1必然完成了 # 3 # 得到task1的任务返回值
max_workers表示线程池最大线程数量。 submit方法提交任务线程给线程池并且返回任务句柄,submit不是阻塞调用,会立刻返回句柄。 cancel方法可以取消提交的任务,如果已经在执行,则无法取消。 result方法获取返回值,这个方法是阻塞的,因为它要等待线程执行完毕才能得到结果。
2、 as_completed 这个方法是一个generator,在某个线程完成之后,使用yield获取结果,如果没有,则阻塞,一直到循环到任务结束。这是个协程的概念。
from concurrent.futures import ThreadPoolExecutor, as_completed import time # 参数times用来模拟网络请求的时间 def get_html(times): time.sleep(times) print("get page {}s finished".format(times)) return times executor = ThreadPoolExecutor(max_workers=2) urls = [3, 2, 4] # 并不是真的url all_task = [executor.submit(get_html, (url)) for url in urls] for future in as_completed(all_task): data = future.result() print("in main: get page {}s success".format(data)) # 执行结果 # get page 2s finished # in main: get page 2s success # get page 3s finished # in main: get page 3s success # get page 4s finished # in main: get page 4s success
3、map executor.map方法,也可以取出结果。使用map方法的时,不用submit。例如:
from concurrent.futures import ThreadPoolExecutor import time # 参数times用来模拟网络请求的时间 def get_html(times): time.sleep(times) print("get page {}s finished".format(times)) return times executor = ThreadPoolExecutor(max_workers=2) urls = [3, 2, 4] # 并不是真的url for data in executor.map(get_html, urls): print("in main: get page {}s success".format(data)) # 执行结果 # get page 2s finished # get page 3s finished # in main: get page 3s success # in main: get page 2s success # get page 4s finished # in main: get page 4s success
注意,这里的输出结果的顺序和map的顺序相同。
3、wait方法 wait可以让主线程阻塞,知道满足要求后,继续执行。他接受3个参数,等待任务序列、超时时间和等待条件,时间上类似event的功能。
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED, FIRST_COMPLETED import time # 参数times用来模拟网络请求的时间 def get_html(times): time.sleep(times) print("get page {}s finished".format(times)) return times executor = ThreadPoolExecutor(max_workers=2) urls = [3, 2, 4] # 并不是真的url all_task = [executor.submit(get_html, (url)) for url in urls] wait(all_task, return_when=ALL_COMPLETED) print("main") # 执行结果 # get page 2s finished # get page 3s finished # get page 4s finished # main
二、总结 python把线程池和进程池放到future模块里。future这个设计,在很多脚本语言里都有,初步接触会麻烦点。future对象也是异步执行的核心。
查看更多关于Python学习第十二课(线程池)的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did163085