多线程、多进程是常用的提高程序执行效率的方法。python中multiprocessing 包支持多进程。
下边是一个简单的多进程demo:
from multiprocessing import Pool
def f(x): # 基本函数返回 x的平方
return x * x
def my_callback(x): # 回调函数,打印x
print(x)
def multicore():
pool = Pool(4) # 创建可容纳四个进程的进程池
for i in range(10): # 从进程池中取出进程执行基本函数f,然后调用回调函数打印结果,执行10次
pool.apply_async(f, args=(i,), callback=my_callback)
pool.close() # 关闭进程池, 不允许再添加新的进程
pool.join() # 等待所有子进程执行完毕
print("test")
if __name__ == '__main__': # 主进程时执行
multicore()
对于这个demo, 我们期望的执行情况是这样的: 先打印出 "test", 然后创建容纳4个进程的进程池, 通过进程池调用进程完成10次循环. 然而实际的执行结果却是这样的(用","替换了换行):
test,test,test,0,1,4,9,16,25,36,49,64,81,test,test
这里print("test")执行了5 次 显然不是我们期望的结果,为什么会这样呢?
为了便于我们分析,现修改部分代码如下:
print("test")
print("%d-------- main out" % os.getpid())
if __name__ == '__main__': # 主进程时执行
print("%d-------- main in" % os.getpid())
multicore()
引入包 os,两处打印进程号,一次在"__main__"模块外, 一次在"__main__"模块内.结果如下:
test
4072-------- main out
4072-------- main in
test
8248-------- main out
test
11932-------- main out
0
1
4
9
16
25
36
49
64
81
test
4892-------- main out
test
4060-------- main out
从上述结果中我们可以看到,"__main__"模块内的getpid()执行了一次, 该模块外的getpid()执行了5次, 其中有一次pid值与"__main__"内的getpid()相同.
由进程的基本概念,我们知道进程分为主(父)进程、子进程。当我们执行 test.py时,执行的进程为主进程, 这时打印出第一个test, getpid()--main out, 因为主进程的__name__值为 "__main__", 因此执行 "__main__"模块, 打印出 getpid()-- main in, 开始调用multicore()方法.
这时线程创建了可容纳四个进程的进程池, 进程池开始一个一个添加进程, 每当添加一个新的进程时, 该进程便会扫描整个py文件,当扫描到
print("test")
print("%d-------- main out" % os.getpid())
便会执行,因此可以看到另外4个 test, 和 pid --- main out.
至此整个分析基本结束, 你也许会问, 子进程扫描的时候, 也扫描到了
if __name__ == '__main__': # 主进程时执行
print("%d-------- main in" % os.getpid())
multicore()
为什么不执行呢?
这是因为子进程的 "__name__"值 不等于 "__main__", 可以打印一下试试
print(__name__)
好了, 整个分析过程就是这样. 简单的说 进程池会创建一批子进程, 这些子进程会把该py文件所有可执行的语句都执行了, 因此不想让子进程执行的语句要放在函数体内, 或者放在
if __name__ == '__main__': # 主进程时执行
语句下边.
如何简单地理解Python中的if __name__ == '__main__'