我是python以及MPI的新手。 我有一个巨大的数据文件,10Gb,我想加载它,即列表或更高效的,请建议。
这是我将文件内容加载到列表中的方式
def load(source, size):
data = [[] for _ in range(size)]
ln = 0
with open(source, 'r') as input:
for line in input:
ln += 1
data[ln%size].sanitize(line)
return data
注意:
用于在python中使用MPI进行并行计算。
请告知如何更有效,更快地加载数据。我搜索了几天,但我无法获得符合我目的的任何结果,如果存在,请在此处注明链接。
此致
答案 0 :(得分:0)
如果我理解了这个问题,那么你的瓶颈就不是Python数据结构。正是I / O速度限制了程序的效率。 如果文件是在H.D.D中的连续块中写入的,那么我不知道比从第一个字节开始到结尾读取文件更快地读取它的方法。 但是如果文件是碎片的,则创建多个线程,每个线程读取文件的一部分。必须减慢读取过程,但现代HDD实现了一种名为NCQ(本机命令队列)的技术。它的工作原理是对地址接近HDD头当前位置的扇区的读操作给予高度优先。因此,使用多个线程提高了读取操作的整体速度。
要为您的程序提供Python中的高效数据结构,您需要提及您将对数据执行哪些操作? (删除,添加,插入,搜索,追加等)以及频率如何?
顺便说一句,如果你使用商用硬件,10GB的RAM是昂贵的。尝试通过加载必要的计算数据,然后用新数据替换结果来进行下一次操作,从而减少对RAM数量的需求。您可以将计算与I / O操作重叠,以提高性能。
答案 1 :(得分:0)
您的任务策略可以这样:
要获得任何收益,您必须小心,因为开销可以克服并行所有可能的收益 运行:
在我的小测试中,我创建了一个包含10万行内容" 98-BBBBBBBBBBBBBB"的文件, " 99-BBBBBBBBBBB"测试将其转换为数字列表[....,98,99,...]。
对于拆分,我使用了Linux命令split
,要求创建4个保留行边界的部分:
$ split -n l/4 long.txt
这会创建较小的文件xaa
,xab
,xac
,xad
。
要转换我在后面脚本中使用的每个较小的文件,将内容转换为文件
扩展名.pickle
并包含腌制列表。
# chunk2pickle.py
import pickle
import sys
def process_line(line):
return int(line.split("-", 1)[0])
def main(fname, pick_fname):
with open(pick_fname, "wb") as fo:
with open(fname) as f:
pickle.dump([process_line(line) for line in f], fo)
if __name__ == "__main__":
fname = sys.argv[1]
pick_fname = fname + ".pickled"
main(fname, pick_fname)
将一大块行转换为腌制记录列表:
$ python chunk2pickle xaa
并创建文件xaa.pickled
。
但是,由于我们需要并行执行此操作,因此我使用了parallel
工具(必须安装到其中)
系统):
$ parallel -j 4 python chunk2pickle.py {} ::: xaa xab xac xad
我在磁盘上找到了扩展名为.pickled
的新文件。
-j 4
要求并行运行4个进程,将其调整到您的系统或将其保留,并将其保留
默认为您拥有的核心数。
parallel
也可以通过ls
等其他方式获取参数列表(在我们的例子中输入文件名)
命令:
$ ls x?? |parallel -j 4 python chunk2pickle.py {}
要整合结果,请使用脚本integrate.py
:
# integrate.py
import pickle
def main(file_names):
res = []
for fname in file_names:
with open(fname, "rb") as f:
res.extend(pickle.load(f))
return res
if __name__ == "__main__":
file_names = ["xaa.pickled", "xab.pickled", "xac.pickled", "xad.pickled"]
# here you have the list of records you asked for
records = main(file_names)
print records
在我的回答中,我使用了几个外部工具(split
和parallel
)。你可能会做类似的任务
用Python也是。我的回答是只关注为您提供保留Python代码的选项
将行转换为所需的数据结构。完整的纯Python答案不在这里(它
会变得更长,也可能更慢。
以下解决方案使用Python的多处理。在这种情况下,不需要腌制结果 显式(我不确定,如果它是由库自动完成的,或者它是没有必要的 数据通过其他方式传递。)
# direct_integrate.py
from multiprocessing import Pool
def process_line(line):
return int(line.split("-", 1)[0])
def process_chunkfile(fname):
with open(fname) as f:
return [process_line(line) for line in f]
def main(file_names, cores=4):
p = Pool(cores)
return p.map(process_chunkfile, file_names)
if __name__ == "__main__":
file_names = ["xaa", "xab", "xac", "xad"]
# here you have the list of records you asked for
# warning: records are in groups.
record_groups = main(file_names)
for rec_group in record_groups:
print(rec_group)
此更新的解决方案仍然假设,大文件以四个较小的文件形式提供。