最简单的方法来执行特定的并行任务?

时间:2013-12-08 16:16:22

标签: python parallel-processing

我们有一个巨大的二进制文件,大约1TB。现在我们要解析它 - 以块的形式迭代它并从每个块中提取一些数据。文件很大,我们真的希望避免拆分或以任何方式复制它,因为它会占用更多的硬盘空间。

现在我们只需逐块读取它并提取数据。简单但不平行。并且它不能在“2行代码”中并行化,因为我们希望避免在多个进程中复制对象(我们没有大量的RAM)。所以基本上我们想要执行10个解析器实例,它们可以在同一台机器上访问同一个内存对象。是的还有另外一种方法,包括减少地图或类似的东西,但我想简化一些事情,并且接近我在本段第一句中描述的最简单的方法。好吧,我当然可以记住偏移量,运行多个进程(每个进程都会从自己的偏移量开始读取文件)等等,但也许有一个很小的库可以自动生成?任务非常简单和常见,任何日志解析都是同一类任务......简单,速度快,内存消耗最少 - 这就是我所需要的全部......没有怪物hadoop集群,没有很长的代码块可写,没有冻结和开销。

谢谢!

1 个答案:

答案 0 :(得分:0)

因此,这里的所有内容都不需要您的工作,不会占用更多内存,不会消耗更多磁盘空间,不会产生任何其他开销,永远不会冻结,并为您提供更好的加速。您只是忘记要求它每隔5个机器周期将钱存入您的银行帐户; - )

说真的,如果它真的 就像你认为的那样简单,那么没有人会打扰为它编写一个库。谁愿意下载呢?如果它很容易,他们可以在睡眠中自己编写,而不必为了理解文档作者可能没有费心去编写的文档而烦恼,因为它是如此微不足道。 / p>

那说,这种方法有什么问题?

def your_func(f, size):
    # Process `size` bytes beginning at the
    # current position in file object `f`,
    # which is open for reading in binary mode.

    # Your processing code goes here, presumably
    # containing one or more instances of
    #     f.read(SOME_NUMBER_OF_BYTES)

# All the rest is machinery to support multiprocessing.
def worker(path, offset, size):
    # Open the file, seek() to the correct offset,
    # invoke the user's processing code, and
    # return the passed-in offset & size for reporting.
    with open(path, "rb") as f:
        f.seek(offset)
        your_func(f, size)
    return (offset, size)

def progress_reporter(args):
    # A callback to report progress.  Optional.
    offset, size = args
    print "finished {:,} bytes at offset {:,}".format(size, offset)

def parallel_chunk(path, chunksize, ncpus=None):
    import os.path
    import multiprocessing

    p = multiprocessing.Pool(ncpus)  # None means all available
    full, leftover = divmod(os.path.getsize(path), chunksize)
    for i in range(full):
        p.apply_async(worker,
                      args=(path, i * chunksize, chunksize),
                      callback=progress_reporter)
    if leftover:
        p.apply_async(worker,
                      args=(path, full * chunksize, leftover),
                      callback=progress_reporter)
    p.close()
    p.join()

if __name__ == "__main__":
    parallel_chunk(YOUR_FILE_PATH, YOUR_CHUNK_SIZE)

这不需要额外的磁盘空间,只需要足够的额外RAM来创建ncpus工作进程。如果文件大小除以chunksize至少与ncpus一样大,则所有ncpus个工作进程将同时运行。进程间通信量很小:只是一个字符串(文件路径)和每个块的几个整数。

但是不能保证它比在单个CPU上运行更快。这取决于您的操作系统,C库和磁盘如何交互的无数细节,以及您的处理功能的详细信息。

可能的问题:如果文件大小除以chunksize很大,多处理机器可能确实在其内部队列中消耗相应大量的RAM来记住所有待处理的任务(它们 all 通过apply_async()调用非常快速地启动 - 在我们到达p.join()之前,此处没有任何内容阻止等待结果。如果这是一个问题,代码需要变得更复杂才能处理它。我只是增加chunksize。但是,所有工作人员可能需要更多RAM(以处理更大的chunksize - 但是否取得的取决于your_func()的作用,并且您没有表明这一点。

玩得开心: - )