使用Python处理不适合内存的文件

时间:2019-10-23 13:01:12

标签: python multiprocessing bigdata

我有一个很大的tar文件(总计700GB),其中包含数百万个XML文件。这些XML文件包含大量垃圾数据,我尝试解析它们,获取所需的详细信息,然后将其存储在CSV中。

我的第一步是将tar文件拆分为较小的文件(每个文件约1-1.5GB)。现在,我需要浏览所有tar文件,阅读它们,获取信息并将其存储在2个不同的CSV文件中。

我的代码:

import tarfile
import csv  
import glob 
from multiprocessing import Process
import xml.etree.ElementTree as ET

def main(index, tar_file):

    tar = tarfile.open(tar_file)

    file1 = open('file1_' + str(index) + '.csv', "w")
    file2 = open('file2_' + str(index) + '.csv', "w")

    writer1 = csv.writer(file1, delimiter=',')
    writer2 = csv.writer(file2, delimiter=',')

    for member in tar:
        if member.isreg() and member.name.endswith('.xml'): # regular xml file
            with closing(tar.extractfile(member)) as xmlfile:
                root = ET.parse(xmlfile).getroot()
                if <statement>:
                    #get the data I want from root
                    writer1.writerow(<some data>)

                if <statement>:   
                    #get the data I want from root      
                    writer2.writerow(<some data>)
    workFile.close()
    peerFile.close()  
    tar.close()               

if __name__ == '__main__':

    files = [f for f in glob.glob("data/*.tar", recursive=True)]  
    procs = []
    for index, f in enumerate(files):
        proc = Process(target=main, args=(index, f,))
        procs.append(proc)
        proc.start()

    for proc in procs:
        proc.join()

我是这样做的,所以我没有在内存中保留任何内容,而是逐行写入文件。但是,在运行上面的代码一段时间后,我的笔记本电脑刚刚关闭。我猜想,代码中有一部分会填满内存。我该如何处理这种情况而无需立即阅读所有内容?

1 个答案:

答案 0 :(得分:1)

目前还不清楚为什么笔记本电脑会关机。可能是“内存不足”和“文件描述符不足”的不良组合(您产生了很多进程,每个进程打开了3个文件,是吗?),可能是操作系统中的错误或某些硬件的故障。

无论哪种方式,您都可以尝试通过减少产生的进程数来避免这种情况。首先,每个文件产生一个进程没有任何好处。经验法则是:产生的并行功能不要超过[3 x内核数]个(通常,当您执行CPU密集型任务时,仅[cores]个就足够了,但是您的I / o很少也是如此)。

所以不是

files = [f for f in glob.glob("data/*.tar", recursive=True)]  
procs = []
for index, f in enumerate(files):
    proc = Process(target=main, args=(index, f,))
    procs.append(proc)
    proc.start()

for proc in procs:
    proc.join()

尝试

from multiprocessing import Pool, cpu_count
pool = Pool(2*cpu_count())  # or 3, do some empirical testing
files = [f for f in glob.glob("data/*.tar", recursive=True)]  
procs = []
for index, f in enumerate(files):
    pool.apply_async(main, (index, f,))

pool.close()
pool.join()

在此处了解有关池的更多信息:https://docs.python.org/2/library/multiprocessing.html#using-a-pool-of-workers

如果您使用的是Python3.x,还可以尝试执行程序:https://docs.python.org/3/library/concurrent.futures.html