「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。
正式的Python专栏第77篇,同学站住,别错过这个从0开始的文章!
前面我们用ProcessPoolExecutor创建进程池的时候,学委特别声明了需要在__main__代码块加载后才可以创建进程池。
那么到底是为啥呢?
首先我们看一下问题,在脚本内直接放创建进程池的代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/2/23 10:20 下午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : processexecutordemo1.py
# @Project : DeepDivePython
import threading
import time
from concurrent.futures.process import ProcessPoolExecutor
from datetime import datetime
def do_something(args):
print("%s process - args %s" % (datetime.now(), args))
print("%s process- - done" % (datetime.now()))
return "end of process"
with ProcessPoolExecutor() as executor:
print("executor:", executor)
executor.submit(do_something, ("学委的Executor Demo "))
读者可以直接复制上面的代码在开发工具运行。
executor: <concurrent.futures.process.ProcessPoolExecutor object at 0x10addb640>
executor: <concurrent.futures.process.ProcessPoolExecutor object at 0x10bb0d310>
RuntimeError: An attempt has been made to start a new process before the current process has finished its bootstrapping phase.This probably means that you are not using fork to start your child processes and you have forgotten to use the proper idiom
这里的意思是,在一个进程完成启动加载阶段之前,我们尝试启动一个进程。然后这个事情被编译器发现了,所以抛出了错误。
另外我们发现打印了多次executor object,而且它们的id还不一样0x10addb640 vs 0x10bb0d310, 也就是说运行过程中创建了多个进程池对象。
可以得出一个结论:
代码被重复加载了多次,导致重复执行了。
为什么代码被执行多次?
因为我们创建进程池的时候,创建的子进程会加载完整模块的代码。
这样碰到进程池创建的代码的时候,又会创建进程池,那么相应的也初始化子进程。
如此迭代,导致了最开始的祖父进程,无法完成自己本身的初始化。
我们通过放在__main__代码块,实现了条件式加载
这样子进程不会碰到进程池创建的代码,也就不会每个子进程,都去创建自己的进程池了。
整个循环加载调用的链路就切断了。
具体代码已经发布在ProcessPoolExecutor的demo文章内了。
这也是学委特别补充编写前篇的原因的,此次不明白这个变化的读者可以翻阅:python脚本不同加载模式下,模块内置属性__name__的取值变化。
喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏
持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!