Python进程池和范围

时间:2009-09-27 19:55:03

标签: python pool

我试图在循环中运行自动生成的代码(可能无法终止),用于遗传编程。我正在尝试使用多处理池,因为我不希望每次都创建一个新进程带来巨大的性能开销,如果它运行时间太长(我不能使用线程),我可以终止池进程。

基本上,我的程序是

if __name__ == '__main__':    
    pool = Pool(processes=1)            
    while ...:
        source = generate() #autogenerate code
        exec(source)
        print meth() # just a test, prints a result, since meth was defined in source
        result = pool.apply_async(meth)
        try:
            print result.get(timeout=3)  
        except:
           pool.terminate()

这是应该工作的代码,但不是,而是我得到

AttributeError: 'module' object has no attribute 'meth'

如果在最顶层定义了Pool,它似乎只能看到meth方法。有任何建议如何让它运行动态创建的方法?

编辑: 问题与Process完全相同,即

source = generated()
exec(source)
if __name__ == '__main__':    
    p = Process(target = meth)
    p.start()

有效,而

if __name__ == '__main__':    
    source = generated()
    exec(source)
    p = Process(target = meth)
    p.start()

没有,并且因AttributeError

而失败

3 个答案:

答案 0 :(得分:3)

您是否阅读过the programming guidelines?关于全局变量的内容很多。 Windows下有更多限制。您没有说明您正在运行哪个平台,但如果您在Windows下运行,则可能会出现问题。从上面的链接

  

全局变量

     

请记住,如果在子进程中运行的代码尝试访问全局变量,那么它看到的值(如果有)可能与Process.start时父进程中的值不同(被叫了。

     

但是,只是模块级常量的全局变量不会引起任何问题。

答案 1 :(得分:2)

Process(通过池或其他方式)将不会__name__ '__main__',因此它不会执行任何取决于该条件的内容 - 包括{{1}当然,您依赖的语句是为了找到exec

为什么你如此热衷于让meth受到一种条件的保护,按照设计,你的子流程中的IS会变错,但是这个子流程依赖 (矛盾的!)执行exec ......?!这真让人难以置信......

答案 2 :(得分:0)

正如我上面评论的那样,你所有的例子都在我的Linux盒子上运行(Debian Lenny,Python2.5,处理0.52,见下面的测试代码)。

对于可以从一个进程传输到另一个进程的对象,窗口似乎有很多限制。阅读Nick指出的文档,似乎在窗口中缺少os,它将运行一个全新的python解释器导入模块和pickle / unpickle应该传递的对象。如果他们不能被腌制,我希望你会遇到你遇到的那种问题。

因此,完整的(非)工作实例可能对诊断有用。答案可能在于您隐藏的内容无关紧要。

from processing import Pool
import os

def generated():
    return (
"""
def meth():
    import time
    starttime = time.time()
    pid = os.getpid()
    while 1:
        if time.time() - starttime > 1:
            print "process %s" % pid
            starttime = starttime + 1

""")


if __name__ == '__main__':
    pid = os.getpid()
    print "main pid=%s" % pid
    for n in range(5):
        source = generated() #autogenerate code
        exec(source)
        pool = Pool(processes=1)            
        result = pool.apply_async(meth)
        try:
            print result.get(timeout=3)  
        except:
           pool.terminate()

另一个建议是使用线程。 是的,您可以,即使您不知道生成的代码是否会停止,或者您生成的代码是否具有不同的嵌套循环。循环没有任何限制,这正是使用生成器(提取控制流)的一个要点。我不明白为什么它不能适用于你正在做的事情。 [同意独立流程可能更多变化]见下面的例子。

import time

class P(object):
    def __init__(self, name):
        self.name = name
        self.starttime = time.time()
        self.lastexecutiontime = self.starttime
        self.gen = self.run()

    def toolong(self):
        if time.time() - self.starttime > 10:
            print "process %s too long" % self.name
            return True
        return False

class P1(P):
    def run(self):
        for x in xrange(1000):
            for y in xrange(1000):
                for z in xrange(1000):
                    if time.time() - self.lastexecutiontime > 1:
                        print "process %s" % self.name
                        self.lastexecutiontime = self.lastexecutiontime + 1
                        yield
        self.result = self.name.uppercase()

class P2(P):
    def run(self):
        for x in range(10000000):
            if time.time() - self.lastexecutiontime > 1:
                print "process %s" % self.name
                self.lastexecutiontime = self.lastexecutiontime + 1
                yield
        self.result = self.name.capitalize()

pool = [P1('one'), P1('two'), P2('three')]
while len(pool) > 0:
    current = pool.pop()
    try:
        current.gen.next()
    except StopIteration:
        print "Thread %s ended. Result '%s'" % (current.name, current.result) 
    else:
        if current.toolong():
            print "Forced end for thread %s" % current.name 
        else:
            pool.insert(0, current)