前言
标准库concurrent.futures模块,它提供了ProcessPoolExecutor和ThreadPoolExecutor两个类,
实现了对threading和multiprocessing的进一步抽象.
1/ThreadPoolExecutor线程池
ThreadPoolExecutor()构造实例的时候,传入[max_workers]()参数来设置线程中最多能同时运行的线程数目
使用submit()函数来提交线程需要执行任务(函数名和参数)到线程池中,并返回该任务的句柄(类似于文件、画图),注意[submit()]()不是阻塞的,而是立即返回。
通过submit()函数返回的任务句柄,能够使用done()()方法判断该任务是否结束
使用result()方法可以获取任务的返回值,查看内部代码,发现这个方法是阻塞的
# -*-coding:utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
import time # 参数times用来模拟网络请求时间
def f(times):
print("get page {}s finished".format(times))
return times
# 构建多线程池子
executor = ThreadPoolExecutor(max_workers=2)
# 通过submit函数提交执行的函数到线程池中,submit函数立即返回,不阻塞
task1 = executor.submit( f,(3) )
task2 = executor.submit( f,(2) )
#done方法用于判断某个任务是否完成
print(task1.done())
#cancel方法用于取消某个任务,该任务没有放到线程池中才能被取消
print(task2.cancel())
print(task1.done())
#result方法可以获取task的执行结果
print(task1.result())
#结果:
# get page 3s finished
# get page 2s finished
# True
# False
# True
# 3
2/ProcessPoolExecutor进程池
有2种任务提交方式
<1>同步提交方式
提交任务,原地等待任务执行结束,拿到任务返回结果,再执行接下来的任务
优点:可以解耦合
缺点:速度慢,因为需要等结果,然后再执行下一个
import datetime
from concurrent.futures import ProcessPoolExecutor
from threading import current_thread
import time, random, os
import requests
def f(name):
print('%s %s is running'%(name,os.getpid()))
#print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
if __name__ == '__main__':
process_pool = ProcessPoolExecutor(4) # 设置进程池内进程数
for i in range(10):
# 同步调用方式,调用和等值
# 传参方式(任务名,参数),参数使用位置或者关键字参数
obj = process_pool.submit(f,"进程pid:")
# .result()函数,得到进程的返回结果,及return的结果
# 如果f()函数中没有return,则obj.result()是None
res = obj.result()
# 关闭进程池的入口,等待池内任务运行结束,再执行主程序
process_pool.shutdown(wait=True)
print("主线程")
<2>异步提交方式
只调用,不等值
优点:速度快
缺点:存在耦合
import datetime
from concurrent.futures import ProcessPoolExecutor
from threading import current_thread
import time, random, os
import requests
def f(name):
print("%s %s is running" %(name,os.getpid()))
time.sleep(random.randint(1,3))
if __name__ == '__main__':
#设置进程池内进程
process_pool = ProcessPoolExecutor(4)
for i in range(10):
# 异步提交方式,只调用,不等值
process_pool.submit(f,'进程pid:')
# 传参方式(任务名,参数),参数使用位置参数或者关键字参数
# 关闭进程池的入口,等待池内任务运行结束,再执行主程序
process_pool.shutdown( wait=True )
print('主线程')
总结
1、线程不是越多越好,会涉及cpu上下文的切换(会把上一次的记录保存)。
2、进程比线程消耗资源,进程相当于一个工厂,工厂里有很多人,里面的人共同享受着福利资源,,一个进程里默认只有一个主线程,比如:开启程序是进程,里面执行的是线程,线程只是一个进程创建多个人同时去工作。
3、线程里有GIL全局解锁器:不允许cpu调度
4、计算密度型(cpu密集型)适用于多进程
4.1 I/O密集型适合多线程,谁有空谁执行
5、线程:线程是计算机中工作的最小单元
6、进程:默认有主线程 (帮工作)可以多线程共存
7、协程:一个线程,一个进程做多个任务,使用进程中一个线程去做多个任务,微线程
8、GIL全局解释器锁:保证同一时刻只有一个线程被cpu调度