并行处理单独模块中的函数

时间:2013-12-25 16:56:47

标签: python python-3.x multiprocessing

我应该是一个“令人尴尬的并行”任务:我正在尝试以CPU重的方式解析许多日志文件。我不关心他们完成的顺序,并且流程不需要共享任何资源或线程。

我在Windows机器上。

我的设置类似于:

main.py

import parse_file
import multiprocessing

...

files_list = ['c:\file1.log','c:\file2.log']

if __name__ == '__main__':
    pool = multiprocessing.Pool(None)

    for this_file in files_list:
        r = pool.apply_async(parse_file.parse, (this_file, parser_config))
        results = r.get()

...

#Code to do stuff with the results

parse_file基本上是一个完全独立的模块,不访问任何共享资源 - 结果以列表形式返回。

当我在没有多处理的情况下运行它时,这一切都运行得非常好,但是当我启用它时,会发生什么事情,我得到一个巨大的错误墙,表明源模块(进入的模块)就是那个平行奔跑。 (错误是仅在源脚本(而不是parse_file模块)中的某个内容的数据库锁定错误,以及在多处理内容之前的某个点!)

我并不是假装理解多处理模块,而是使用other示例here,但没有一个包含任何表明这是正常的或者为什么会发生这种情况。

我做错了什么?如何多任务处理此任务? 谢谢!


使用此功能可轻松复制: test.py

import multiprocessing
import test_victim

files_list = ['c:\file1.log','c:\file2.log']

print("Hello World")

if __name__ == '__main__':
    pool = multiprocessing.Pool(None)
    results = []
    for this_file in files_list:
        r = pool.map_async(test_victim.calculate, range(10), callback=results.append)
        results = r.get()

    print(results)

test_victim.py:

def calculate(value):
    return value * 10

运行test.py时的输出应为:

Hello World
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

但实际上它是:

Hello World
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
Hello World
Hello World

(额外的“Hello World”的实际数量)每次在1到4之间运行时都会改变=应该没有)

1 个答案:

答案 0 :(得分:1)

在Windows上,当Python执行时

pool = multiprocessing.Pool(None) 

产生了新的Python进程。由于Windows没有os.fork,因此这些新的Python进程会重新导入调用模块。因此,任何不在里面的东西

if __name__ == '__main__': 

为每个生成的进程执行一次。这就是为什么你会看到多个Hello Worlds

请务必阅读文档中的"Safe importing of main module"警告。


所以要修复,将所有需要在

中只需运行一次的代码
if __name__ == '__main__': 

语句。


例如,您的可运行示例将通过放置

来修复
print("Hello World")

if __name__ == '__main__'语句中:

import multiprocessing
import test_victim

files_list = ['c:\file1.log','c:\file2.log']

def main():
    print("Hello World")
    pool = multiprocessing.Pool(None)
    results = []
    for this_file in files_list:
        r = pool.map_async(test_victim.calculate, range(10), callback=results.append)
        results = r.get()

    print(results)

if __name__ == '__main__':
    main()

产量

Hello World
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

特别是在Windows上,使用multiprocessing的脚本必须既可以运行(作为脚本)又可以导入。使脚本可导入的简单方法是如上所示构造它。放置脚本应在名为main的函数中执行的所有内容,然后使用

if __name__ == '__main__':
    main()

在脚本的末尾。 main之前的东西应该只是import语句和全局常量的定义。