2012-02-07 103 views
7

我在python中编写了一个多线程解压缩程序。每个线程需要访问不同的输入文件块。从python中的多个线程读取单个文件

注1:无法加载整个文件,因为它的范围从15 Gb到200 Gb;我没有使用多线程来加速数据读取,但数据解压缩,我只是想确保数据读取不会减慢解压。注意2:GIL不是问题,在这里,由于主解压缩函数是一个C扩展,它调用Py_ALLOW_THREADS,所以GIL在解压缩时被释放。第二阶段减压使用也是无GIL的numpy。

1)我认为这是行不通的去分享一个解压缩对象(这基本上包装了一个文件对象),如果线程A调用以下日期:

decompressor.seek(x) 
decompressor.read(1024) 

和线程B不相同,螺纹A可能最终从线程B偏移量读取。它是否正确?

2)现在我只是让每个线程创建自己的Decompressor实例,它似乎工作,但我不知道这是最好的方法。 我考虑这些可能性:

  • 添加类似

    seekandread(from_where, length) 
    

    到获取锁时,寻求,读取和释放锁解压缩类;

  • 创建一个线程,等待读取请求并按正确的顺序执行它们。

那么,我是否错过了一个明显的解决方案?这些方法之间是否存在显着的性能差异?

感谢

+5

以多线程方式读取文件实际上会减慢硬盘驱动器进程的速度。针必须从一个地方跳到另一个地方,而不是以迭代方式工作。您应该在处理文件之前加载文件。 – 2012-02-07 12:16:17

+0

无法加载整个文件,因为它的范围从15 Gb到200 Gb;我没有使用多线程来加速数据读取,但数据解压缩,我只是想确保数据读取不会减慢解压。 – Alberto 2012-02-07 12:21:16

+0

当然,这可能或可能不适用于SSD。我不知道这个问题。您不应该在硬件上进行中继。一旦SSD足够普及,以多线程方式执行I/O可能会很有效。 – 2012-02-07 12:21:56

回答

2

您可以使用mmap。请参阅mmap() vs. reading blocks

正如Tim Cooper指出的那样,当您有随机访问权限(多线程会使您看起来像您拥有这个)时,mmap是一个好主意,并且他们可以共享相同的物理页面。

+0

这似乎很棒!我查看了mmap的python文档,但找不到有关线程安全性的参考。如果2个线程同时执行类似a = mappedfile [x:y]的操作,它是否会按预期工作? – Alberto 2012-02-07 13:47:37

+0

为了回答我自己,看起来python mmap切片符号实际上是线程安全的。我创建了一个测试程序,用于从不同线程访问mmapped文件的不同部分,并检查结果。如果我使用切片符号,它会通过测试,如果我使用seek/read,则失败。不过,我仍然需要检查性能。 – Alberto 2012-02-07 16:30:25

+1

@Alberto:在我看来,任何已经被处理的给定段应该至少由一个互斥量保护,如果不是一个有条件的信号量抛出。通过抛出有条件的信号量,我的意思是一个信号量不会等待直到它出现时才会满足事件前条件,而是抛出异常。它是一个信号量和gaurd之间的混合体。您可能只想在条件B不满足时抛出,如果满足条件A则等待。 – 2012-02-07 19:33:56

2

你可能想,如果你不这样做,已经使用Leader/Follower模式。
Leader线程将知道哪些段已被处理,哪些不处理,并将自身分配给下一个未处理的段,然后成为跟随者,将领导留在池中的下一个可用线程。

+0

谢谢,我会考虑这一点。 – Alberto 2012-02-07 12:29:51

1

CPython有GIL,因此多个线程不会提高CPU绑定任务的性能。

如果问题不是IO限制(磁盘提供/存储数据比CPU更快解压缩),则可以使用multiprocessing module:每个进程打开文件并解压缩给定的字节范围。

+1

主解压缩函数是一个C扩展,它调用Py_ALLOW_THREADS,以便在解压缩时释放GIL。第二阶段减压使用numpy也是无gil的。我已经测量了一个很好的加速。 – Alberto 2012-02-07 13:32:17

+0

(也许这个澄清 - 关于你有“照顾”的GIL - 也可以进入问题主体) – jsbueno 2012-02-07 15:43:07

+0

10你是对的,完成 – Alberto 2012-02-07 16:25:25

相关问题