Loading

python 多进程

背景:串行执行慢,考虑使用多进程来加速。

1 多进程

这块可以参考:https://blog.csdn.net/Hao_ge_666/article/details/120571731

2 多线程

这块可以参考:https://blog.csdn.net/Hao_ge_666/article/details/120603014

3 进程池

参考:https://zhuanlan.zhihu.com/p/568073350

当任务需求重,需要并发更多的进程时,每次手动维护多进程则会变得不太方便。python 提供了进程池的相关能力,通过指定一个固定资源量的进程池,在进程池中开启或回收进程,整体管理由进程池维护。

3.1 基础模版
# 实例化一个进程池对象,max_workers 设置进程池中能同时运行的最大进程数目,如果不指定默认为 cpu 的核数
pool = ProcessPoolExecutor(max_workers=3)

# submit是非阻塞方法,提交一个函数到进程池中,返回一个 future 对象
future1 = pool.submit(target_func, param)

# 关闭进程池
pool.shutdown()

# 与全局函数 map 类似, 将启动多个线程,以异步方式立即对 iterable 执行 map 处理
pool.map(func, iterable)
或者采用 with 写法,使用完毕自动回收:
with ProcessPoolExecutor(max_workers=3) as pool:
	pool.submit(target_func, param)
3.2 获取进程相关信息的函数
future1.done()   # 判断 future 代表的任务是否执行完成

future1.result()   # 获取 future 代表的任务结果,该方法为阻塞方法,timeout 参数可以指定最多阻塞多少秒

future1.cancel()   # 取消 future 代表的任务,执行中的任务取消不了,返回 bool

future1.add_done_callback(func)   # 为 future代表任务注册一个回调函数,任务执行完成之后会自动调用该函数,被调用的函数默认接收一个 feture 对象

as_completed()   # 接收一个 future 列表,返回一个生成器,通过迭代能够获取到每一个 future 的结果。
其中 result() 可以获取进程函数的返回结果。
3.3 for 循环多进程任务开启&运行

举个栗子:当我们需要同时验证一批代理 ip 是否可用时,串行的对每个 ip 运行一次检查逻辑显然并不是一个高效的做法,为了加速验证,可以借助进程池,下面是示例代码

from concurrent.futures import ProcessPoolExecutor
from tqdm import tqdm	# 一个进度条组件


def check_proxy_icanhazip(ip, port):
	print('test func')
	return True

all_proxies = [
	{'ip':'11.11.11.11', 'port':'111'}, {'ip':'22.22.22.22','port':'222'}
]	# 待验证代理

print(f'IP 验证,主进程开始执行, pid:{os.getpid()}')

# with 方式开启进程池
with ProcessPoolExecutor(max_workers=50) as pool:
	# 循环的对每个代理进行验证
	for proxy in tqdm(all_proxies, desc='checking proxies...'):
		# 向进程池中提交一次验证操作
		task = pool.submit(check_proxy_icanhazip, proxy['ip'], proxy['port'])

但是,当每个进程有自己的返回结果并且我们要使用该结果做进一步处理时,上述方法无法定位到每个进程的返回结果,此时可借助 as_completed:

def check_proxy_icanhazip(ip, port):
	print('test func')
	return True, {'ip': ip, 'port': port}

all_proxies_filter = dict()

# 方式2:as_completed() 方式来接收一个 future 列表
# 这种方式会收集每个子进程的运行结果
pool = ProcessPoolExecutor(max_workers=len(spiders))
all_task = [pool.submit(check_proxy_icanhazip, (proxy['ip'], proxy['port'])) for proxy in all_proxies]
for future in as_completed(all_task):
    res, proxy = future.result()
    print(f"res: {res}")
	print('proxy': proxy)
	if res:
		all_proxies_filter[proxy['ip']] = proxy

print(all_proxies_filter)
posted @ 2023-04-09 19:25  sinatJ  阅读(19)  评论(0编辑  收藏  举报