【发布时间】:2021-07-12 01:18:24
【问题描述】:
几天前,我回复了question on SO,关于并行读取 tar 文件。
这是问题的要点:
import bz2
import tarfile
from multiprocessing import Pool
tr = tarfile.open('data.tar')
def clean_file(tar_file_entry):
if '.bz2' not in str(tar_file_entry):
return
with tr.extractfile(tar_file_entry) as bz2_file:
with bz2.open(bz2_file, "rt") as bzinput:
# Reading bz2 file
....
....
def process_serial():
members = tr.getmembers()
processed_files = []
for i, member in enumerate(members):
processed_files.append(clean_file(member))
print(f'done {i}/{len(members)}')
def process_parallel():
members = tr.getmembers()
with Pool() as pool:
processed_files = pool.map(clean_file, members)
print(processed_files)
def main():
process_serial() # No error
process_parallel() # Error
if __name__ == '__main__':
main()
正如the answer 中提到的那样,我们只需在子进程而不是父进程中打开 tar 文件即可使错误消失。
我无法理解为什么会这样。
即使我们在父进程中打开tarfile,子进程也会得到一个新的副本。 那么为什么在子进程中打开 tarfile 会显式地产生任何影响呢?
这是否意味着在第一种情况下,子进程以某种方式改变了公共 tarfile 对象并由于并发写入而导致内存损坏?
【问题讨论】:
-
open创建一个绑定到进程的文件句柄。在类 UNIX 系统上,它只是一个数字。该数字对于其他进程并不意味着相同。 -
您可以在here987654323@这个主题上找到一篇有趣的帖子
-
当我回答您的原始问题时,我发布了代码,展示了如何初始化池中的每个进程以打开 tar 文件,就像您在上面尝试做的那样,每个进程只打开一次池中的进程,而不是每个被提取的成员。你试过运行代码吗?
-
@Booboo 我不是问这个问题的人。我是回答它的人。我试过你的答案,效果很好。其实你和我的回答基本上是一样的。
-
@AnmolSinghJaggi 我似乎错过了这一点。我突然想到,正如 OP 应该在提出带有
regex标记的问题时指定使用的语言一样,OP 应该在发布带有multiprocessing标记的问题时指定使用的平台。我之前的评论适用于使用spawn的平台,例如Windows。在我对原始问题的回答中,我还建议 OP 使用spawn。
标签: python concurrency parallel-processing multiprocessing python-multiprocessing