【问题标题】:Throttling Popen() calls限制 Popen() 调用
【发布时间】:2013-09-20 21:34:23
【问题描述】:

在初始 Popen 解决之前使用 Popen() 启动过多进程有多大危险?

我正在对一个充满 PDF 的目录进行一些处理。我遍历每个文件并使用外部调用做两件事。

首先,我从基于 Xpdf 的 pdftohtml 工具(pdfminer 太慢)中获得了一个 html 表示。这只会输出第一页:

html = check_output(['pdftohtml.exe','-f','1','-l','1','-stdout','-noframes',pdf])

然后如果满足我的条件(我确定它是正确的文档),我会在其上调用 tabula-extractor 以提取表格。与检查文档相比,这是一个缓慢/长时间运行的过程,并且只发生在大约 1/20 个文件上。

如果我只是做call(['jruby', 'C:\\jruby-1.7.4\\bin\\tabula', .....]),我会花很长时间等待提取完成,同时我可以检查更多文件(我有 4 个内核和 16gb 的内存,而且 Tabula 似乎不是多线程的) .

因此,我使用 Popen() 来避免阻塞。

Popen(['jruby', 'C:\\jruby-1.7.4\\bin\\tabula', '-o', csv, '-f', 'CSV', '-a', "'",topBorder, ',', leftBorder, ',', bottomBorder, ',', rightBorder, "'", '-p', '1', pdf]) 
#where CSV is the name of the output file and pdf is the name of the input

我不关心返回值(tabula 正在创建一个 csv 文件,所以我总是可以在事后查看它是否成功创建)。这样做意味着我可以继续在后台检查文件并根据需要启动更多的制表进程(同样,只有大约 20 分之一)。

这可行,但它会积压并最终一次运行大量的 tabula 进程。所以我的问题是: 这很糟糕吗?它使计算机在其他任何事情上都变慢,但只要它不崩溃并且尽可能快地工作,我并不介意(所有 4 个内核一直处于 100% 的状态,但内存使用量不会) t 超过 5.5GB,因此它看起来受 CPU 限制)。

如果不好,改善它的正确方法是什么?有没有一种方便的说法,将 tabula 进程排队,这样每个内核总是运行 1-2 个,但我不想一次处理 30 个文件?

【问题讨论】:

  • 每个核心 2 个过多。我相信一个好的起始数字是每个内核 1 + 1(以防其他内核需要一点 I/O)来提高吞吐量。

标签: python multithreading tabula


【解决方案1】:

有没有一种方便的说法,将制表进程排队,这样每个内核总是运行 1-2 个,但我不想一次处理 30 个文件?

是的,multiprocessing 模块就是这样做的。

import multiprocessing
import subprocess

def process_pdf(path):
    subprocess.call(['jruby', 'C:\\jruby-1.7.4\\bin\\tabula', path, ...])

pool = multiprocessing.Pool(3)      # 3 processes
results = []
for path in search_for_files():
    results.append(pool.apply_async(process_pdf, [path]))
for result in results:
    result.wait()

【讨论】:

  • 我不确定你是否应该像这样对进程进行分层......也许坚持使用线程(?)。不过,在这种情况下,您会想使用 concurrent.futures
  • 在我看来,我必须首先拥有我的文件列表才能使其正常工作。所以我不能在生成 tabula 进程的同时继续扫描列表,我必须按顺序进行。
  • @otto - 你肯定想要multiprocessing。您需要查看该模块中的 Queue 类以完全实现您所描述的内容。您将产生 2 - 3 个消费者,您的主要流程是您的生产者,当它们通过您的初始条件时,您将项目添加到队列中。
  • @otto 别担心,我们已经为您提供了保障——请参阅更新的答案。
  • 我正在努力完成这项工作。它似乎并没有只产生 3 个进程。相反,它产生了无限数量的进程(如果我查看进程列表,它会在几秒钟内迅速从约 100 个基数变为超过 1000 个)。看起来它实际上并没有对进程进行排队。
猜你喜欢
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2012-04-02
  • 1970-01-01
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
相关资源
最近更新 更多