线程池使用
from concurrent.futures import ThreadPoolExecutor, as_completed, wait, FIRST_COMPLETEDfrom concurrent.futures import Futurefrom multiprocessing import Pool#未来对象,task的返回容器#线程池, 为什么要线程池#主线程中可以获取某一个线程的状态或者某一个任务的状态,以及返回值#当一个线程完成的时候我们主线程能立即知道#futures可以让多线程和多进程编码接口一致import timedef get_html(times): time.sleep(times) print("get page {} success".format(times)) return timesexecutor = ThreadPoolExecutor(max_workers=2)#通过submit函数提交执行的函数到线程池中, submit 是立即返回task1 = executor.submit(get_html, (3))task2 = executor.submit(get_html, (2))#要获取已经成功的task的返回# 1.waitexecutor = ThreadPoolExecutor(max_workers=2)urls = [3,2,4]all_task = [executor.submit(get_html, (url)) for url in urls]# return_when默认值是全部完成返回,可以增加超时时间参数wait(all_task, return_when=FIRST_COMPLETED) # 2.as_completed (submit + as_completed获取任务结果) ## all_task是多个任务 ## 获取任务结果顺序: 谁先执行成功则返回谁的结果for future in as_completed(all_task): data = future.result() print("get {} page".format(data))# 3.map 提交任务 + 获取任务结果#通过executor的map获取已经完成的task的值 ## urls是参数列表,交给get_html函数同时执行 ## map返回结果顺序与urls参数列表顺序一致for data in executor.map(get_html, urls): print("get {} page".format(data))#done方法用于判定某个任务是否完成print(task1.done())print(task2.cancel()) ##取消任务time.sleep(3)print(task1.done())#result方法可以获取task的执行结果 #获取单个任务结果print(task1.result())# 使用案例1with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: all_task=[executor.submit(main,ip,survival_ip_pool) for ip in ip_pool] ip_pool_fail=[] #失败ip池 for future in as_completed(all_task,timeout=40): ipx,status = future.result() if not status: ip_pool_fail.append(ipx)# 使用案例2 executor = ThreadPoolExecutor(max_workers=MAX_WORKERS) # 线程池为1000 for ip in ip_pool: f = executor.submit(ping_ip, ip) # 提交即异步执行 executor.shutdown() # 等待所有进程执行完毕后,关闭线程池。 return ip_list# 使用案例3 # 多线程执行main ip_pool_fail=[] #失败ip池 executor=ThreadPoolExecutor(max_workers=MAX_WORKERS) all_task=[executor.submit(main,ip,survival_ip_pool,ip_pool_fail) for ip in ip_pool] wait(all_task,timeout=50) //阻塞50秒后不阻塞
gil说明
gil global interpreter lock (cpython)python中一个线程对应于c语言中的一个线程gil使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行gil会根据执行的字节码行数以及时间片释放gil,gil在遇到io的操作时候主动释放 import dis def add(a): a = a+1 return a print(dis.dis(add))