并行Python:如何向'提交'提供参数?

6 投票
2 回答
3778 浏览
提问于 2025-04-15 14:58

这是关于parallel-python标签的第二个问题。我查阅了文档并在网上搜索了相关内容,最终来到这里,因为我在这里得到的答案和建议最有效。

下面是我提交所有相关信息给pp的API(我想这是它的名字)。

    def submit(self, func, args=(), depfuncs=(), modules=(),
        callback=None, callbackargs=(), group='default', globals=None):
    """Submits function to the execution queue

        func - function to be executed
        args - tuple with arguments of the 'func'
        depfuncs - tuple with functions which might be called from 'func'
        modules - tuple with module names to import
        callback - callback function which will be called with argument
                list equal to callbackargs+(result,)
                as soon as calculation is done
        callbackargs - additional arguments for callback function
        group - job group, is used when wait(group) is called to wait for
        jobs in a given group to finish
        globals - dictionary from which all modules, functions and classes
        will be imported, for instance: globals=globals()
    """

这是我的提交语句和它的参数:

job_server.submit(reify, (pop1, pop2, 1000), 
                  depfuncs = (key_seq, Chromosome, Params, Node, Tree), 
                  modules = ("math",), 
                  callback = sum.add, globals = globals())

depfuncs中,所有大写的名字都是类的名称。我不太确定应该把这些类放在哪里,或者是否需要包含它们,因为它们已经在globals()字典中了。但是当我用空的depfuncs()运行时,会出现像“Tree not defined”这样的错误。

现在,key_seq是一个生成器,所以我必须使用它的一个实例才能使用.next()

def key_seq():
    a = 0
    while True:
        yield a
        a = a + 1
ks = key_seq()

ks是在globals()中定义的。当我没有在其他地方包含它时,出现了“ks is not defined”的错误。当我把ks包含在depfuncs中时,出现了这个错误:

Traceback (most recent call last):
  File "C:\Python26\Code\gppp.py", line 459, in <module>
    job_server.submit(reify, (pop1, pop2, 1000), depfuncs = (key_seq, ks, Chromosome, Params, Node, Tree), modules = ("math",), callback = sum.add, globals = globals())
  File "C:\Python26\lib\site-packages\pp.py", line 449, in submit
    sfunc = self.__dumpsfunc((func, ) + depfuncs, modules)
  File "C:\Python26\lib\site-packages\pp.py", line 634, in __dumpsfunc
    sources = [self.__get_source(func) for func in funcs]
  File "C:\Python26\lib\site-packages\pp.py", line 713, in __get_source
    sourcelines = inspect.getsourcelines(func)[0]
  File "C:\Python26\lib\inspect.py", line 678, in getsourcelines
    lines, lnum = findsource(object)
  File "C:\Python26\lib\inspect.py", line 519, in findsource
    file = getsourcefile(object) or getfile(object)
  File "C:\Python26\lib\inspect.py", line 441, in getsourcefile
    filename = getfile(object)
  File "C:\Python26\lib\inspect.py", line 418, in getfile
    raise TypeError('arg is not a module, class, method, '
TypeError: arg is not a module, class, method, function, traceback, frame, or code object

我很确定arg是指ks。那么,我应该在哪里告诉.submit()关于ks的事情呢?我不太明白应该把什么放在哪里。谢谢。

2 个回答

0

我觉得你应该传入 lambda:ks.next(),而不是直接传 ks。

5

有趣,你是在做基因模拟吗?我问这个是因为我看到里面有“染色体”这个词,而我之前用并行Python开发过一个种群遗传学的模拟。

你的方法看起来挺复杂的。在我的并行Python程序中,我用了下面这个调用:

job = jobServer.submit( doRun, (param,))

我怎么能做到这一点呢?诀窍在于doRun函数并不是在你调用submit的那个上下文中运行的。举个例子:

import os, pp

def doRun(param):
    print "your name is %s!" % os.getlogin()

jobServer = pp.Server()
jobServer.submit( doRun, (param,))

这段代码会失败。原因是os模块在doRun中不存在——doRun并不是在submit的同一个上下文中运行。当然,你可以把os作为submitmodule参数传进去,但在doRun中直接调用import os不是更简单吗?

并行Python试图通过在一个完全独立的进程中运行你的函数来避免Python的全局解释器锁(GIL)。它试图通过让你“传递”参数和命名空间给你的函数来让这个过程更容易理解,但这实际上是用一些小技巧实现的。例如,你的类会使用某种变体的pickle进行序列化,然后在新进程中反序列化。

但与其依赖submit的这些小技巧,不如接受现实:你的函数需要自己完成设置运行上下文的所有工作。实际上,你有两个main函数——一个是设置调用submit的,另一个是通过submit调用的,真正负责设置你需要完成的工作的。

如果你需要从生成器中获取下一个值以供并行运行,也要把它作为参数传递!这样可以避免使用lambda函数和生成器引用,直接传递一个简单的变量就行了!

我的代码现在不再维护了,但如果你感兴趣,可以在这里查看: http://pps-spud.uchicago.edu/viewvc/fps/trunk/python/fps.py?view=markup

撰写回答