【问题标题】:How can I process a tarfile with a Python multiprocessing pool?如何使用 Python 多处理池处理 tarfile?
【发布时间】:2011-11-24 07:40:55
【问题描述】:

我正在尝试使用multiprocessing.Pool 处理 tar 文件的内容。我能够在多处理模块中成功使用 ThreadPool 实现,但希望能够使用进程而不是线程,因为它可能会更快并消除为 Matplotlib 处理多线程环境所做的一些更改。我收到一个错误,我怀疑与进程不共享地址空间有关,但我不确定如何修复它:

Traceback (most recent call last):
  File "test_tarfile.py", line 32, in <module>
    test_multiproc()
  File "test_tarfile.py", line 24, in test_multiproc
    pool.map(read_file, files)
  File "/ldata/whitcomb/epd-7.1-2-rh5-x86_64/lib/python2.7/multiprocessing/pool.py", line 225, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/ldata/whitcomb/epd-7.1-2-rh5-x86_64/lib/python2.7/multiprocessing/pool.py", line 522, in get
    raise self._value
ValueError: I/O operation on closed file

实际的程序更复杂,但这是我正在做的一个重现错误的示例:

from multiprocessing.pool import ThreadPool, Pool
import StringIO
import tarfile

def write_tar():
    tar = tarfile.open('test.tar', 'w')
    contents = 'line1'
    info = tarfile.TarInfo('file1.txt')
    info.size = len(contents)
    tar.addfile(info, StringIO.StringIO(contents))
    tar.close()

def test_multithread():
    tar   = tarfile.open('test.tar')
    files = [tar.extractfile(member) for member in tar.getmembers()]
    pool  = ThreadPool(processes=1)
    pool.map(read_file, files)
    tar.close()

def test_multiproc():
    tar   = tarfile.open('test.tar')
    files = [tar.extractfile(member) for member in tar.getmembers()]
    pool  = Pool(processes=1)
    pool.map(read_file, files)
    tar.close()

def read_file(f):
    print f.read()

write_tar()
test_multithread()
test_multiproc()

我怀疑当TarInfo 对象被传递到另一个进程但父TarFile 不是时出现问题,但我不确定如何在多进程情况下修复它。我可以在不必从 tarball 中提取文件并将它们写入磁盘的情况下执行此操作吗?

【问题讨论】:

    标签: python multiprocessing tarfile


    【解决方案1】:

    您没有将TarInfo 对象传递给另一个进程,而是将tar.extractfile(member) 的结果传递给memberTarInfo 对象的另一个进程。 extractfile(...) 方法返回一个类似文件的对象,其中包含一个 read() 方法,该方法对您使用 tar = tarfile.open('test.tar') 打开的原始 tar 文件进行操作。

    但是,您不能在另一个进程中使用来自一个进程的打开文件,您必须重新打开该文件。我用这个替换了你的test_multiproc()

    def test_multiproc():
        tar   = tarfile.open('test.tar')
        files = [name for name in tar.getnames()]
        pool  = Pool(processes=1)
        result = pool.map(read_file2, files)
        tar.close()
    

    并添加了这个:

    def read_file2(name):
        t2 = tarfile.open('test.tar')
        print t2.extractfile(name).read()
        t2.close()
    

    并且能够让您的代码正常工作。

    【讨论】:

    • Windows 支持:if name == '__main__': test_multiproc()。 Windows 中没有分叉,因此模块最初以名称'__parents_main__' 导入到新进程中,然后名称改回'__main__'。因此,您可以使用if 块来保护您不想在子进程中运行的语句。
    • 这可行,但需要我在每个进程中重新打开 tar 文件。是否有任何其他解决方法允许在进程之间对文件描述符进行只读访问?
    • 我最终设置了一个标志以在多个进程分叉之前预读取数据。谢谢!
    猜你喜欢
    • 2021-07-24
    • 2020-08-14
    • 2016-11-10
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 2014-08-25
    相关资源
    最近更新 更多