【问题标题】:Python Multiprocessing And Argument Passing Help Needed需要 Python 多处理和参数传递帮助
【发布时间】:2014-03-19 04:58:41
【问题描述】:

您好,我正在尝试运行文档中的多处理示例:http://docs.python.org/3.4/library/concurrent.futures.html,使用素数但差异很小。

我希望能够调用具有多个参数的函数。我正在做的是将小段文本(在大约 30k 长的列表中)匹配到更大的一段文本,并返回较大字符串中较小字符串的开始位置。

我可以像这样连续执行此操作:

matchList = []
for pattern in patterns:

    # Approximate pattern matching
    patternStartingPositions = processPattern(pattern, numMismatchesAllowed, transformedText, charToIndex, countMatrix, firstOccurrence, suffixArray)

    # Now add each starting position found onto our master list.
    for startPos in patternStartingPositions:
        matchList.append(startPos)

但我想这样做是为了加快速度:

matchList = []
with concurrent.futures.ProcessPoolExecutor() as executor:
    for pattern, res in zip(patterns, executor.map(processPattern(pattern, numMismatchesAllowed, transformedText, charToIndex, countMatrix, firstOccurrence, suffixArray), patterns)):
        print('%d is starts at: %s' % (pattern, res))

在这个阶段,我刚刚收到了 print 调用,因为我无法获得上面的行,即进程的调用工作。

我想要做的和示例代码之间唯一真正的区别是我的函数需要 7 个参数,但我不知道该怎么做,花了半天时间。

上面的调用会产生这个错误:

UnboundLocalError:赋值前引用了局部变量“模式”。

这是有道理的。

但是,如果我忽略第一个参数,它会随着每次调用而改变,并忽略 processPattern 函数的第一个参数:

matchList = []
with concurrent.futures.ProcessPoolExecutor() as executor:
    for pattern, res in zip(patterns, executor.map(processPattern(numMismatchesAllowed, transformedText, charToIndex, countMatrix, firstOccurrence, suffixArray), patterns)):
        print('%d is starts at: %s' % (pattern, res))

然后我得到这个错误:

TypeError: processPattern() 缺少 1 个必需的位置参数:'suffixArray'。

我不知道如何在调用中获取pattern 参数!

【问题讨论】:

    标签: python-3.x multiprocessing argument-passing


    【解决方案1】:

    要将数据转换为正确的形状,只需使用生成器表达式(根本不需要zip)并使用submit 而不是map

    (pattern, executor.submit(processPattern, pattern, ...) for pattern in patterns)
    

    为确保所有内容都在池中执行(而不是立即执行),请不要像在示例中那样调用 processPatterns 函数,而是将其作为第一个参数传递给 .submit。您的代码的固定版本是:

    with concurrent.futures.ProcessPoolExecutor() as executor:
        for pattern, res in ((pattern, executor.submit(processPattern, pattern, numMismatchesAllowed, transformedText, charToIndex, countMatrix, firstOccurrence, suffixArray)) for pattern in patterns):
            print('%d is starts at: %s' % (pattern, res.result()))
    

    【讨论】:

    • executor.submit 返回一个future,所以你应该调用.result() 来取回值
    • @PeterGibson - 好点!感谢您帮助改进答案!
    • 我是 Stackoverflow 新手 :) 我将此标记为正确答案,但代码包含语法错误......中间线......将看看我能做些什么。大声笑,对不起大家,感谢所有的帮助。
    • @davo36 - 已修复(生成器表达式应该创建元组,但不是)。
    • @Sean Vieera,再次感谢伙计。这也是我找到的解决方法。现在 frikkin 的事情挂了......另一个问题。
    【解决方案2】:

    其他海报已经介绍了可能的解决方案,但为了解释您的错误,您应该将函数和参数作为单独的对象传递给 executor.map。这是文档中的示例

    with concurrent.futures.ProcessPoolExecutor() as executor:
        # is_prime is the function, PRIMES are the arguments
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)): 
            print('%d is prime: %s' % (number, prime))
    

    您的代码正在评估processPattern 函数并将结果传递给executor.map

    with concurrent.futures.ProcessPoolExecutor() as executor:
        for pattern, res in zip(patterns, executor.map(processPattern(numMis... # <- BAD
            print('%d is starts at: %s' % (pattern, res))
    

    应该是

    with concurrent.futures.ProcessPoolExecutor() as executor:
        for pattern, res in zip(patterns, executor.map(processPattern, <stuff>)):
            print('%d is starts at: %s' % (pattern, res))
    

    其中&lt;stuff&gt; 是在每次后续调用时传递给processPattern 的可迭代参数。

    或者,看到其他 args 保持不变,创建一个函数,它只接受您正在迭代的一个参数并将 patterns 作为可迭代对象传递(正如 @uhbif19 所建议的那样)

    编辑:

    要详细说明如何创建 &lt;stuff&gt; 可迭代对象,您需要为函数所需的每个参数提供一个可迭代对象(在本例中为 processPattern)。您已经将 patterns 作为参数一的可迭代对象,如果其他参数不变,则 itertools.repeat 可能会有所帮助:

    from itertools import repeat
    args = (patterns, 
            repeat(numMismatchesAllowed, len(PATTERNS)),
            repeat(transformedText, len(PATTERNS)),
            repeat(charToIndex, len(PATTERNS)),
            <etc...>
            )
    

    然后

    for pattern, res in zip(PATTERNS, executor.map(process, *args)):
    

    为了便于理解,我将其包含在内,但您可以看到这是多么混乱。其他答案提供了更好的解决方案。

    编辑 2:

    这里有一个例子可以更好地说明 submit vs map 的使用

    import concurrent.futures
    
    def process(a, b):
        return a.upper() + b
    
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for c, fut in [(c, executor.submit(process, c, 'b')) for c in 'testing']:
            print(c, fut.result())
    
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for c, res in zip('testing', executor.map(process, 'testing', 'bbbbbbb')):
            print(c, str(res))
    

    【讨论】:

    • 谢谢你,是的,这很糟糕,但我也尝试过你所说的。问题是我不知道 会是什么。我知道它应该是一个参数列表,但是我如何获得不断变化的“模式”参数以及那一行上不变的其他 6 个参数?使用提交,我猜它更容易分解。
    • @davo36 我已经更新了答案来解释如何创建&lt;stuff&gt;
    • 对,是的,我确实考虑了编辑 1 中的方法,但知道必须有更好的方法。我可以遵循 executor.submit 示例,但对 executor.map 方法有点困惑。您正在通过 'testing' 和 'bbbbbb' 作为可迭代对象,对吗?再说一次,不知道如何在不重复的情况下将其转化为实际的论点。
    【解决方案3】:

    Python for-loop 是函数式的行为,不能改变值,就是迭代。

    with concurrent.futures.ProcessPoolExecutor() as executor:
    
        def work(pattern):
            return processPattern(pattern, numMismatchesAllowed, transformedText, charToIndex, countMatrix, firstOccurrence, suffixArray)
    
        results = executor.map(work, patterns)
    
        for pattern, res in zip(patterns, results):
            print('%d is starts at: %s' % (pattern, res)) 
    

    事实上,对于不使用 continuebreak 指令的循环,其工作原理就像一个映射函数。那就是:

    for i in something:
        work(i)
    

    相当于

    map(work, something)
    

    【讨论】:

    • 好的,使用中介工作功能的不错的解决方案。
    • 不幸的是,这个解决方案挂在我的电脑上......令人沮丧。
    • @davo36 可能是您的另一个代码中的问题。尝试用普通的map来改变executor.map。代码仍然挂起吗?
    • 不,它不能正常工作。它运行,并得到部分正确的答案并正常终止。我不知道为什么会这样。我会花点时间研究一下。干杯。
    • 好的,现在它可以工作了,只有地图。但是在使用 executor 时它不会执行任何代码,即 processPattern 函数甚至没有被调用。我正在调查这一点,即使文档中的示例在某些情况下也会挂起。我在 Windows 8.1、Intel i4770k、Python 3.3 上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    相关资源
    最近更新 更多