Обрабатывать файлы, которые не помещаются в памяти с Python - PullRequest
1 голос
/ 23 октября 2019

У меня есть большой tar-файл (всего 700 ГБ), который содержит несколько миллионов файлов XML. Эти XML-файлы содержат много мусорных данных, и я пытаюсь их проанализировать, получить необходимую информацию и вместо этого сохранить их в CSV-файле.

Моим первым шагом было разделение файла tar на более мелкие (~ 1-1,5 ГБ каждый) файлы. Теперь мне нужно просмотреть все файлы 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 Ответ

1 голос
/ 23 октября 2019

Не совсем понятно, почему ваш ноутбук выключается. Это может быть плохая комбинация «недостаточно памяти» и «дескрипторов файла» (вы порождаете множество процессов, и каждый открывает 3 файла, да?) И, возможно, ошибка в вашей ОС или сбой какого-либо оборудования.

В любом случае вы можете попытаться избежать этого, просто уменьшив количество порождаемых процессов. Прежде всего, нет никакой выгоды от запуска процесса на файл. Эмпирическое правило: никогда не создавайте больше, чем, скажем, [3 x число ядер] параллельных функций (обычно достаточно [количество ядер], когда вы выполняете задачи с исключительно интенсивной загрузкой процессора, но у вас есть небольшое количество операций ввода-вывода). а также).

Так что вместо

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...