我试图通过使用multiprocessing
库中的Pool
来分配查找历史股票价格数据的任务。
这个工作很好,直到我试图使用我得到的数据。我定义了hist_price
函数,它输出一个字典列表pcl
。我可以print(pcl)
,它是完美的,但是如果我在if __name__=='__main__':
块之后尝试print(pcl)
,它就会爆炸,说pcl
是未定义的。我已经尝试在几个地方声明global pcl
,但它没有区别。
from multiprocessing import Pool
syms = ['List', 'of', 'symbols']
def hist_price(sym):
#... lots of code looking up data, calculations, building dicts...
stlh = {"Sym": sym, "10D Max": pcmax, "10D Min": pcmin} #simplified
return stlh
#global pcl
if __name__ == '__main__':
pool = Pool(4)
#global pcl
pcl = pool.map(hist_price, syms)
print(pcl) #this works
pool.close()
pool.join()
print(pcl) #says pcl is undefined
#...rest of my code, dependent on pcl...
我也试过删除if __name__=='__main__':
块,但它给了我一个RunTimeError告诉我具体把它放回去。是否有其他方法调用变量使用if
块之外?
我认为你的问题有两部分。第一个是"当前代码中的pcl
有什么问题?",第二个是"为什么我需要if __name__ == "__main__"
保护块?"
让我们按顺序来处理它们。pcl
变量的问题是它只在if
块中定义,所以如果模块被加载而没有作为脚本运行(这是设置__name__ == "__main__"
的内容),则在后面的代码运行时不会定义它。
要解决这个问题,您可以更改代码的结构。最简单的修复方法是保护if __name__ == "__main__"
块中使用pcl
的其他代码位(例如,也许将它们全部缩进到当前块下)。另一种修复方法是将使用pcl
的代码放入函数中(可以在保护块外声明),然后从if __name__ == "__main__"
块内调用这些函数。它看起来像这样:
def do_stuff_with_pcl(pcl):
print(pcl)
if __name__ == "__main__":
# multiprocessing code, etc
pcl = ...
do_stuff_with_pcl(pcl)
至于为什么这个问题首先出现,最终原因是在Windows上使用multiprocessing
模块。您可以在文档中阅读有关该问题的信息。
当multiprocessing为它的Pool
创建一个新进程时,它需要用当前模块状态的副本初始化该进程。因为Windows没有fork
(它会自动将父进程的内存复制到子进程中),所以Python需要从头开始设置所有内容。在每个子进程中,它从它的文件中加载模块,如果你的模块的顶层代码试图创建一个新的Pool
,你会有一个递归的情况,每个子进程将开始产生一套自己的全新的子进程。
multiprocessing
代码有一些防范措施,我认为(所以你不会因为简单的粗心而fork bomb自己),但是你仍然需要自己做一些工作,通过使用if __name__ == "__main__"
来保护任何不应该在子进程中运行的代码。