我一直在使用multiprocessing
软件包来加速某些地理处理(GIS/arcpy
)任务,这些任务是多余的,需要对2000多个类似的几何图形执行相同的操作。在
分拆工作很好,但我的“工人”职能相当长和复杂,因为任务本身从头到尾都很复杂。我想把这些步骤分解得更详细一些,但是在向worker函数传递信息/从worker函数传递信息时遇到了困难,因为出于某种原因,多处理下的worker函数使用的任何东西都需要显式地传入。在
这意味着我不能在if __name__ == '__main__'
的主体中定义常量,然后在worker函数中使用它们。这也意味着我的worker函数的参数列表变得非常长,这是非常难看的,因为尝试使用多个参数还需要创建一个helper“star”函数,然后itertools
将它们重新压缩(这是this question上的第二个答案)。在
我在下面创建了一个小例子来演示我所说的。有什么解决办法吗?我应该用一种不同的方法,或者至少有人能解释一下为什么会这样?在
注意:我正在Windows Server 2008 R2 Enterprise x64上运行此程序。在
编辑:我的问题似乎还不够清楚。我不太关心pool.map
如何只接受一个参数(尽管这很烦人),但是我不理解为什么在if __name__ == '__main__'
之外定义的函数的作用域不能访问该块中定义的内容,如果它被用作多处理函数,除非您显式地将其作为参数传递,这是令人讨厌的。在
import os
import multiprocessing
import itertools
def loop_function(word):
file_name = os.path.join(root_dir, word + '.txt')
with open(file_name, "w") as text_file:
text_file.write(word + " food")
def nonloop_function(word, root_dir): # <------ PROBLEM
file_name = os.path.join(root_dir, word + '.txt')
with open(file_name, "w") as text_file:
text_file.write(word + " food")
def nonloop_star(arg_package):
return nonloop_function(*arg_package)
# Serial version
#
# if __name__ == '__main__':
# root_dir = 'C:\\hbrowning'
# word_list = ['dog', 'cat', 'llama', 'yeti', 'parakeet', 'dolphin']
# for word in word_list:
# loop_function(word)
#
## --------------------------------------------
# Multiprocessing version
if __name__ == '__main__':
root_dir = 'C:\\hbrowning'
word_list = ['dog', 'cat', 'llama', 'yeti', 'parakeet', 'dolphin']
NUM_CORES = 2
pool = multiprocessing.Pool(NUM_CORES, maxtasksperchild=1)
results = pool.map(nonloop_star, itertools.izip(word_list, itertools.repeat(root_dir)),
chunksize=1)
pool.close()
pool.join()
问题是,至少在Windows上(尽管对于*nix
fork
样式的多处理也有类似的警告),当您执行脚本时,它(为了极大地简化它)实际上就像您用subprocess.Popen()
调用两个空(shell)进程,然后让它们执行:一旦其中一个进程用上一个调用结束,就逐个执行。这意味着你的
if __name__ == "__main__"
块永远不会被执行(因为它不是主脚本,它是作为模块导入的),因此它内部声明的任何内容都不容易被函数使用(因为它从未被计算)。在对于你职能之外的员工,你至少可以通过
sys.modules["your_script"]
或者甚至使用globals()
访问你的module
进行欺骗,但这只对被评估的员工有效,因此放在if __name__ == "__main__"
保护内的任何东西都不可用,因为它甚至没有机会。这也是为什么你必须在Windows上使用这个保护的原因-没有它,你将执行你的池创建,以及你嵌套在这个保护内的其他代码,一次又一次地与每个派生的进程一起执行。在如果需要在多处理函数中共享只读数据,只需在脚本的全局命名空间中,在
__main__
保护之外定义它,那么所有函数都可以访问它(因为在启动新进程时,它会被重新计算),而不管它们是否作为单独的进程运行。在如果您需要改变的数据,那么您需要使用能够在不同进程上进行自我同步的东西——有很多模块是为此设计的,但是大多数时候Python自己的基于pickle的数据报通信
multiprocessing.Manager
(以及它提供的类型)就足够了,尽管速度慢而且不太灵活。在没有任何限制,只有它必须是一个可接受的!
尝试一个
class Container
,例如:相关问题 更多 >
编程相关推荐