所以,这是我的情况。
我在Eclipse中使用PyDev,在Windows中使用Python解释器2.7.2版本。
我正在使用内置的多处理库,试图派生出一堆进程来并行化一个计算密集型的循环。我看过的教程说要使用
if __name__ == "__main__":
以防止它产生近乎无限的过程,并使我的系统屈服。
问题是,我从一个模块调用它,而不是从我的主脚本调用它;因此,它之后再也不会被执行。根本没有并行的机会。当然,如果我删除它,我会收到导致执行代码的机器死亡的infiniprocess垃圾邮件。
为了便于参考,以下是相关代码:
from tribe import DataCache
from tribe import WorldThread
from tribe import Actor
from time import sleep
import multiprocessing
class World:
def __init__(self,numThreads,numActors,tickRate):
print "Initalizing world..."
self.cache = DataCache.DataCache()
self.numThreads = numThreads
self.numActors = numActors
self.tickRate = tickRate
self.actors = []
self.processes = []
for i in range(numActors):
self.actors.append(Actor.Actor("test.xml",self.cache))
print "Actors loaded."
def start_world(self):
print "Starting world"
run_world = True;
while run_world:
self.world_tick()
sleep(2)
def world_tick(self):
if __name__ == '__main__':
print "World tick"
actor_chunk = len(self.actors)/self.numThreads
if len(self.processes)==0:
for _ in range(self.numThreads):
new_process = multiprocessing.Process(WorldThread.WorldProcess.work, args=(_, self.actors[_*actor_chunk,(_+1)*actor_chunk]))
它所调用的类:
class WorldProcess():
def __init__(self):
print "World process initilized."
''' Really, I'm not sure what kind of setup we'll be doing here yet. '''
def work(self, process_number, actors):
print "World process" + str(process_number) + " running."
for actor in actors:
actor.tick()
print "World process" + str(process_number) + " completed."
我的评估是正确的吗?整个ifname=="main":check只有在可执行脚本中才有效?如果是这样的话,如何从模块中安全地分出流程?如果没有,为什么它在这里不起作用?
添加这个作为答案,因为它在注释中:
if __name__ == "__main__"
是在将要成为入口点的脚本的根级别上执行的操作。这是一种只有在直接执行脚本时才能执行的方法。
如果您有一个作为入口点的脚本,则执行name==main。在一个想要多处理的模块中,只需像循环和启动线程一样循环和启动进程。
要控制进程数量,请使用multiprocessing
:中的Pool
类
from multiprocessing import Pool
p = Pool(5)
def f(x):
return x*x
p.map(f, [1,2,3])
(编辑:根据注释,这只是Pool类的howto。查看更多)
不需要使用__name__
,因为您显式地将实际的python函数传递给Process
以运行。
此:
def world_tick(self):
if __name__ == '__main__':
print "World tick"
actor_chunk = len(self.actors)/self.numThreads
if len(self.processes)==0:
for _ in range(self.numThreads):
new_process = multiprocessing.Process(WorldThread.WorldProcess.work, args=(_, self.actors[_*actor_chunk,(_+1)*actor_chunk]))
非常糟糕。简化它。
更好的模式是:
class WorkArgs(object):
... many attributes follow ...
def proc_work(world_thread, work_args):
world_thread.WorldProcess.work(work_args.a, work_args.b, ... etc)
p = Pool(5)
p.map(proc_work, [(world_thread, args0), (world_thread, args1), ...])
希望这能有所帮助!
附带说明一下,对参数进行酸洗并将其传递给其他进程将导致导入模块。因此,最好确保您的模块不会预处理任何分叉/魔术/工作,除非有人告诉它(例如,只有函数/类定义或__name__
魔术,而不是实际的代码块)。