多处理 Python 3

Posted

技术标签:

【中文标题】多处理 Python 3【英文标题】:Multiprocessing Python 3 【发布时间】:2020-05-07 06:52:58 【问题描述】:

我一直在尝试为python 3上的一系列任务创建一个多处理池。任务如下: 1. 通读 pdf 文件并捕获 pdf 文件中的表格,然后 - 2.创建一个pickle文件来存储表对象 3. 加载pickle文件

出于测试目的,我在三个 pdf 文件上以序列化和并行化模式运行了 python 代码。排序是在 200 秒内运行整个过程,并在工作目录中创建泡菜文件。但是,多处理不会在目录中生成 pickle 文件,而是需要 39 秒才能运行该进程。

排序代码如下:

os.chdir('C:/Users/dir_path')

    def process_table(pdf):
        for pdf in pdfs:
            tables = camelot.read_pdf(pdf, pages = 'all', flag_size=True, copy_text=['v'], line_scale=40) 
            print(f'Process os.getpid() Processing File Name:pdf\nTotal Tables found:len(tables)')
            with open(pdf.split('.pdf')[0] + '.pkl', 'wb') as f:
                pickle.dump(tables, f)
                print(f'Process os.getpid() Pickle file created for: pdf')
            with open(pdf.split('.pdf')[0] + '.pkl', 'rb') as g:
                pickle.load(g)
                print(f'Process os.getpid() Pickle file loaded: pdf')

    def process_handler():    
        start_time = time.time()
        pdfs = [file_name for file_name in os.listdir()]
        process_table(pdfs)
        end = time.time()
        duration = round(time.time() - start_time)
        print(f'Whole Process completed in duration second(s)') 


if __name__ == '__main__':
    process_handler()    

代码输出如下:

Output of Serialising 多处理代码如下:

os.chdir('C:/Users/dir_path')

def process_table(pdf):
        tables = camelot.read_pdf(pdf, pages = 'all', flag_size=True, copy_text=['v'], line_scale=40) 
        print(f'Process os.getpid() Processing File Name:pdf\nTotal Tables found:len(tables)')
        with open(pdf.split('.pdf')[0] + '.pkl', 'wb') as f:
            pickle.dump(tables, f)
            print(f'Process os.getpid() Pickle file created for: pdf')
        with open(pdf.split('.pdf')[0] + '.pkl', 'rb') as g:
            pickle.load(g)
            print(f'Process os.getpid() Pickle file loaded for: pdf')

def process_handler():    
    start_time = time.time()

    files = [file_name for file_name in os.listdir()]
    with ThreadPoolExecutor() as executor:
        executor.map(process_table, files)

    duration = round(time.time() - start_time)
    print(f'Whole Process completed in duration second(s)') 

if __name__ == '__main__':
    process_handler()

非常感谢您对此提出宝贵意见。这是至关重要的,因为有时 20 MB 的 pdf 文件需要很长时间才能转换为其中存储有表对象的 pickle 文件。因此,该进程停留在第一个作业(即大小为 20 MB 的 pdf)上,并且在第一个作业完成之前无法移动到下一个作业。

谢谢

【问题讨论】:

【参考方案1】:

一些物品;

我只使用了我发现运行良好的多处理池。 process_table 在 map 函数之外被 pdfs 调用,串行处理也是如此。 据我所知,work_items 不包含任何内容,除了 None。 您使用列表参数 (pdf) 调用 process_table,然后使用全局 pdfs 变量。

我会建议类似的东西;

import multiprocessing as mp

files = [file_name for file_name in os.listdir()]
with mp.Pool(mp.cpu_count()-1) as pool:
    pool.map(files, process_table)

【讨论】:

我尝试了您建议的方法,但似乎 jupyter notebook 挂起,我不得不手动中断代码处理。相反,我尝试了以下代码块:files = [file_name for file_name in os.listdir()] with ThreadPoolExecutor() as executor: executor.map(process_table, files) 该代码需要 22 秒才能完成该过程,这几乎是序列化时间的 1/10。但是,我没有看到在我的工作目录中创建和保存的泡菜文件 @Nipun 不要忘记在process_table 中删除pdfs 上的迭代。我不明白为什么它不会写任何东西 - 检查你认为它正在写入的路径。您是否从打印语句中得到任何输出? 运行代码后只有一个输出:'整个过程在 39 秒内完成'。除此之外,它不会打印其他语句,也不会在工作目录中创建泡菜文件。我已根据您的建议更新了我的代码,我发现处理时间现在减少到 39 秒。我不知道为什么它昨天显示了 22 秒。我已经编辑了我上面的帖子,现在包含了更新的代码 @Nipun,您发布的代码不太有效,但看起来使用 ThreadPoolExecutor 您必须使用可迭代的结果,否则它不会做任何事情;所以for r in executor.map(process_table, pdfs): print(r) 感谢您的另一次更新!我确实尝试过这个并得到了ghostscript错误。我忘了提到的一件事是camelot依赖ghostscript,所以在运行多处理代码时需要在后面激活ghostscript.exe文件。您认为代码对另一个工具的依赖可能是多处理代码不起作用的原因吗?

以上是关于多处理 Python 3的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.X 多处理增强 Python 失败

如何结合python多处理和管道技术?

Python 3 中的 Concurrent.futures 与多处理

Python 3多处理 - 如何执行单个任务

Python 多处理与多线程相结合

用于在 MacOS 上复制随机数的 Python 3.8 多处理