Python中处理大文件的最快方法

11

我们需要处理各种目录中大约500GB的图像。每个图像大小约为4MB,我们有一个Python脚本可以逐个处理每个图像(读取元数据并将其存储在数据库中)。每个目录的处理时间根据大小不同可能需要1-4小时。

我们使用GNU/Linux操作系统上的2.2GHz四核处理器和16GB的RAM。当前脚本只利用一个处理器。如何充分利用其他核心和RAM加快图像处理速度?启动多个Python进程来运行脚本是否能利用其他核心呢?

另一种选择是使用像Gearman或Beanstalk这样的工具将工作分配给其他机器。我已经查看了multiprocessing库,但不确定如何使用。


可能是如何在Windows 7中使用所有内核?的重复问题。 - user177800
1
如果您已经有一个可以指向任何文件/目录的工作脚本,请考虑编写一个shell脚本来启动您需要的多个实例。 - Brendan Wood
4
我会从瓶颈处入手。如果你花费大部分时间执行IO操作,那么你不可能跑得更快。例如,如果一个单独的进程以一定的速度从磁盘中读取数据,当多个进程争夺磁盘资源时,你很难保持这个速度。 - Jeff Foster
我非常赞同Jeff Forster的观点,首先要寻找瓶颈。如果您对文件执行的唯一处理是读取元数据并存储它们,则瓶颈很可能是磁盘访问。因此,尝试添加更多访问相同磁盘的进程只会降低性能。 - Tom97531
6个回答

6
“如果任务是CPU密集型的,启动多个Python进程来运行脚本将利用其他核心。”这可能是最简单的选择。但是,不要为每个文件或目录生成单个进程;考虑使用类似于parallel(1)的工具,并让它生成每个核心的两个进程左右。
“另一个选择是使用Gearman或Beanstalk之类的工具将工作分配给其他计算机。”
“这可能有效。此外,请查看ZeroMQ的Python绑定, 它使得分布式处理非常容易。”
“我已经看过了multiprocessing库,但不确定如何利用它。”
“定义一个函数,比如process,它读取单个目录中的图像,连接到数据库并存储元数据。让它返回一个表示成功或失败的布尔值。让directories成为要处理的目录列表。然后”
import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count())
success = all(pool.imap_unordered(process, directories))

这将同时处理所有目录。如果您希望在文件级别上进行并行处理,则需要进行一些微调。

请注意,这将在第一个失败时停止;要使其具有容错性需要更多的工作。


4
你可以使用多进程池来创建进程以提高性能。假设你有一个处理图像的函数handle_file。如果你使用迭代,它最多只能使用一个核心的100%。为了利用多个核心,池化多进程会为你创建子进程,并将你的任务分配给它们。以下是一个示例:
import os
import multiprocessing

def handle_file(path):
    print 'Do something to handle file ...', path

def run_multiprocess():
    tasks = []

    for filename in os.listdir('.'):
        tasks.append(filename)
        print 'Create task', filename

    pool = multiprocessing.Pool(8)
    result = all(list(pool.imap_unordered(handle_file, tasks)))
    print 'Finished, result=', result

def run_one_process():
    for filename in os.listdir('.'):
        handle_file(filename)

if __name__ == '__main__':
    run_one_process
    run_multiprocess()

run_one_process 是处理数据的单核方式,简单但速度较慢。另一方面,run_multiprocess 创建 8 个工作进程,并将任务分配给它们。如果您有 8 个核心,则大约快 8 倍。我建议您将工作进程数设置为您核心数的两倍或正好等于您的核心数。您可以尝试并查看哪种配置更快。
对于高级分布式计算,您可以使用 larsmans 提到的 ZeroMQ。一开始很难理解。但是一旦您理解了它,就可以设计一个非常高效的分布式系统来处理您的数据。在您的情况下,我认为一个 REQ 和多个 REP 就足够了。

enter image description here

希望这对您有所帮助。

4

独立启动Python进程是理想的。这样可以避免进程之间发生锁争用,操作系统会安排它们并发运行。

您可能希望进行实验以确定最佳实例数量-它可能比核心数多或少。磁盘和缓存内存将会有竞争,但另一方面,您可能会让一个进程在等待I/O时运行另一个进程。


2

请看这个答案,它回答了这个问题

如果应用程序可以处理输入数据的范围,那么您可以启动4个应用程序实例,每个实例使用不同的输入数据范围进行处理,最后再组合所有结果。

尽管该问题看起来是针对Windows的,但它适用于所有操作系统上的单线程程序。

警告:请注意,此过程将受到I/O限制。过多的并发访问硬盘实际上会导致进程作为一个整体比顺序处理更慢,因为它们争夺I/O资源。


0
我觉得在这种情况下,使用Celery是非常合理的选择。

0

如果你正在读取大量文件并将元数据保存到数据库中,那么你的程序不需要更多的内核。

你的进程很可能是IO受限而不是CPU受限。使用适当的defereds和回调来使用twisted可能会比试图利用4个内核的任何解决方案都要好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接