Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.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_Multiprocessing_Python Multiprocessing - Fatal编程技术网

在生成器上进行Python多处理,该生成器在

在生成器上进行Python多处理,该生成器在,python,multiprocessing,python-multiprocessing,Python,Multiprocessing,Python Multiprocessing,我正在尝试读取和处理1000个文件,但不幸的是,处理文件的时间大约是从磁盘读取文件的3倍,因此我希望在读取这些文件时(以及在继续读取其他文件时)处理这些文件 在一个完美的世界中,我有一个生成器,它一次读取一个文件,我想将这个生成器传递给一个工作人员池,这些工作人员在生成器中的项目(缓慢)生成时对其进行处理 下面是一个例子: def process_file(file_string): ... return processed_file pool = Pool(proces

我正在尝试读取和处理1000个文件,但不幸的是,处理文件的时间大约是从磁盘读取文件的3倍,因此我希望在读取这些文件时(以及在继续读取其他文件时)处理这些文件

在一个完美的世界中,我有一个生成器,它一次读取一个文件,我想将这个生成器传递给一个工作人员池,这些工作人员在生成器中的项目(缓慢)生成时对其进行处理

下面是一个例子:

def process_file(file_string):
     ...
     return processed_file

 pool = Pool(processes=4)
 path = 'some/path/'
 results = pool.map(process_file, (open(path+part,'rb').read() for part in os.listdir(path)))

上面代码的唯一问题是,在池开始之前,所有文件都被读取到内存中,这意味着我需要等待磁盘读取所有文件,而且我还消耗了大量内存

Pool.map
Pool.map\u async

各种
Pool.imap*
函数似乎将输入处理为生成器,因此您可以更改:

results = pool.map(process_file, (open(path+part,'rb').read() for part in os.listdir(path)))
致:

并且在处理之前不发出咕噜声就可以得到相同的结果,但是在AICT中,他们仍然会尽可能快地完全填充队列,这可能会导致大量未完成的数据和过度的内存使用;除此之外,您将在一个进程中读取所有数据,然后通过IPC发送所有数据,这意味着您在I/O方面仍然处于瓶颈状态

在您的位置,我会将读取内容移动到任务本身中(如果可以,请避免读取整个文件,按行或按块处理,而不是一次读取整个文件)。您将获得并行读取,更少的IPC,并且在处理前几个文件之前,您不会冒着吞咽所有文件的风险;打开的文件永远不会比打开的工作人员多。因此,最终结果如下所示:

def process_file(path):
     with open(path, 'rb') as f:
         file_string = f.read()
     ... same as before ...
     return processed_file

pool = Pool(processes=4)
path = 'some/path/'
results = pool.imap(process_file, (os.path.join(path, part) for part in os.listdir(path)))

您正在将文件读入父级内存,然后将有效负载传输到子级。那是相当低效的。只发送文件名,让孩子们做I/O。如果结果是一堆你计划写入文件的文本,也在孩子们身上做

map
通常会一次性发布大量工作,以减少与池工作人员的通信开销。这可能就是为什么你会有大的记忆尖峰。只传递文件名就可以解决这个问题,但是当工作人员之间的处理时间不均匀时,设置一个小的chunksize仍然是有益的

def process_file(filename):
     with open(filename, 'rb') as fp:
         file_string = fp.read()
     ...
     return processed_file

 pool = Pool(processes=4)
 path = 'some/path/'
 results = pool.map(process_file, path+part for part in os.listdir(path)), chunksize=1)

尝试为
pool.map()
调用指定一个
chunksize
参数,以控制一次将iterable的多少个元素作为单独的任务提交给
pool
。如果有多个子项尝试读取文件,我相信这将导致交叉磁盘读取和磁盘抖动?@mgoldwaser-它可以,但是,您希望让一些工作人员在其他人忙于处理数据时提取数据,从而保持磁盘通道的正常运行。当数据头飞过数据时,队列重新排序有一些好处。4名工人阅读时,你不会有明显的颠簸。这种方法确实有效,并且大大缩短了时间。事实证明,使用
imap()
而不是
map()
会给您带来最大的好处。感谢您的更新。多处理调整在现实世界中的工作方式令人惊讶。如果多个孩子试图读取文件,我相信这会导致交叉磁盘读取和磁盘抖动?@mgoldwaser:取决于存储介质;在NFS上,您通常受到延迟或每连接带宽的限制,例如,超过了同步读取的限制。需要进行测试以确定这是否是性能问题。如果读取块或行而不是读取整个文件(正如我在回答中所建议的,尽管我缺乏提供有用示例的信息),块读取之间所做的工作可能会减少冲突。或者,在slurping时,可以使用单个
多处理.Lock
将每次读取限制为单个工作者。最佳选择因环境而异。MGoldwaser,您可以测量它;)只需比较两种可能的解决方案:使用产量的矿山和使用多处理读取的@ShadowRanger。因为它依赖于硬件/软件/网络…@ShadowRanger,所以将文件读取移到process_file函数中对运行时间没有影响。使用
imap()
是提高速度的真正关键-谢谢!
def process_file(filename):
     with open(filename, 'rb') as fp:
         file_string = fp.read()
     ...
     return processed_file

 pool = Pool(processes=4)
 path = 'some/path/'
 results = pool.map(process_file, path+part for part in os.listdir(path)), chunksize=1)