Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python多处理:全局对象未正确复制到子对象_Python_Concurrency_Parallel Processing_Multiprocessing_Python Multiprocessing - Fatal编程技术网

Python多处理:全局对象未正确复制到子对象

Python多处理:全局对象未正确复制到子对象,python,concurrency,parallel-processing,multiprocessing,python-multiprocessing,Python,Concurrency,Parallel Processing,Multiprocessing,Python Multiprocessing,几天前,我回答了一个关于并行读取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_ent

几天前,我回答了一个关于并行读取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()
我们可以通过在子进程中而不是在父进程中打开tar文件来消除错误,如中所述

我不明白为什么会这样

即使我们在父进程中打开tarfile,子进程也将获得一个新副本。 那么,为什么在子进程中打开tarfile会有明显的区别呢


这是否意味着在第一种情况下,子进程以某种方式改变了公共tarfile对象,并由于并发写入而导致内存损坏?

FWIW,注释wrt
open
中关于文件句柄号的答案在类UNIX系统上实际上是不正确的

如果
multiprocessing
使用
fork()
(它在Linux和类似系统下使用,尽管我读到macOS上的fork存在问题),文件句柄和其他所有内容都会被愉快地复制到子进程中(通过“愉快地”我的意思是,它在许多边缘情况下(例如分叉线程)都很复杂,但对于文件句柄来说仍然可以正常工作)

以下对我来说很好:

导入多处理
此=打开(_文件__,'r')
def read_文件():
打印(len(this.read())
def main():
process=multiprocessing.process(目标=read\u文件)
process.start()
process.join()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
问题很可能是,
tarfile
在读取时具有内部结构和/或缓冲,而且,如果同时尝试查找和读取同一归档文件的不同部分,您可能会遇到冲突。也就是说,我推测在这种情况下,使用线程池而不进行任何同步可能会遇到完全相同的问题

编辑:为了澄清,从Tar归档文件中提取文件很可能(我没有检查确切的细节)如下所述:(1)查找封装部件(文件)的偏移量,(2)读取封装文件的块,将块写入目标文件(或管道,或w/e),(3)重复(2)直到整个文件被提取

通过使用同一个文件句柄从并行进程尝试非同步的方式,可能会导致这些步骤的混合,即开始处理文件第2个将从文件第1条中寻找,而我们处于读取文件1的中间,等等

Edit2回答下面的评论:内存表示是为子进程重新分叉的,这是真的;但是在内核端管理的资源(如文件句柄和内核缓冲区)是共享的

举例说明:

导入多处理
this=open(_文件_,'rb')
def read_文件(工作程序):
打印(工人,本。读取(80))
def main():
进程=[]
对于(1,2)中的数字:
进程.append(
Process(target=read\u文件,args=(number,))
对于过程中的过程:
process.start()
对于过程中的过程:
process.join()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
在Linux上运行此操作,我得到:

$ python3.8 test.py 
1 b"import multiprocessing\n\nthis = open(__file__, 'rb')\n\n\ndef read_file(worker):\n   "
2 b''

如果搜索和读取是独立的,这两个过程将打印相同的结果,但它们不是。因为这是一个小文件,Python选择缓冲少量数据(8kib),所以第一个进程读取EOF,第二个进程没有数据可读取(当然,除非它返回)。

open
创建一个绑定到进程的文件句柄。在类UNIX系统上,它只是一个数字。这个数字对其他过程来说并不相同。当我回答你最初的问题时,你可以找到一篇关于这个主题的有趣帖子,我发布了一些代码,展示了如何初始化池中的每个进程,以像上面尝试的那样打开tarfile,从而使池中的每个进程只打开一次tarfile,而不是为提取的每个成员打开tarfile。你试过运行代码吗?@Booboo我不是问这个问题的人。是我回答的。我试过你的答案,效果很好。事实上,你和我的答案基本上是一样的。@AnmolSinghJaggi我似乎忽略了这一点。我突然想到,正如OP应该指定在询问带有
regex
标记的问题时使用的语言一样,OP应该指定在发布带有
多处理
标记的问题时使用的平台。我之前的评论适用于使用
spawn
的平台,如Windows。在我对原始问题的回答中,我还建议OP使用
spawn
。但是tarfile的内存表示应该重新复制到每个子进程中;那么,一个搜索将如何干扰另一个搜索呢?你是指磁盘上的实际文件吗?在这种情况下,OSX(或任何现代操作系统)不保证多个进程同时读取单个文件吗?事实上,这就是为什么第二个程序没有错误@AnmolSinghJaggi看到更新的答案;我指的是磁盘上的实际源文件,它在竞争读取和查找操作的工作人员之间共享。在回答时,我确实假设选择fork()的Unix Python,我的回答在macOS上可能无效:您是对的。当我们使用fork方法时,文件偏移量以某种方式在进程之间共享。然而,在spawn下,我们得到2个完全不同的文件句柄。如果您在程序顶部编写
multiprocessing.set\u start\u method('spawn')
,您将注意到不同的输出。