@DimkaI
Системный адинистратор, разработчик ПО

Где утекает память при работе с zip и ods?

Здравствуйте! Подскажите, почему и где утекает память при работе кода без дочерних процессов? Вроде все данные очищаю, удаляю и примерно на середине списка уже выжирается вся память как оперативная, так и файла подкачки.
Код python 3
#!/bin/python3
# -*- coding: utf-8 -*-
#
# Получение информации о кадастровой стоитмости земельных участков. Так как среди всех тех актов невозмодно найти в каком именно 
# внесены данные о участке, то сделал такой код, который скачивает все файлы, и создаёт csv файл со списком кадастровых
# данных и в каком файле они расположены.
# чтобы узнать с каком файле ваш акт, достаточно  ввести команду:
#    cat kadastr.csv | grep "50:00:0000000:0"
# где "50:00:0000000:0" - кадастровый номер вашего участка
# Данные находятся в открытом источнике, согласно рассылка от ИФНС:
# С предварительными результатами новой кадастровой стоимости вы сможете ознакомиться 1 августа 2022 года.
# Они будут опубликованы на официальных сайтах Министерства имущественных отношений Московской области 
# https://mio.mosreg.ru/ и Центра кадастровой оценки https://ckomo.ru/
#
# Исходный код расположен https://github.com/DimkaInc/Kadastr


import os, sys
# os.system("python3 -m pip install requests beautifulsoup4 pyexcel pyexcel-ods3 --upgrade")
import requests, zipfile, pyexcel as pe
from bs4 import BeautifulSoup
from urllib.parse import urlencode

# Работа в одном файле или через вызов дочернего процесса
only_one = True
# Создание файла результата с нуля
renew_file = True

pg_url = "https://ckomo.ru/01.01.05.14/329"
html_text = requests.get(pg_url).text
soup = BeautifulSoup(html_text, 'html.parser')
base_url = "https://cloud-api.yandex.net/v1/disk/public/resources/download?"

out_file_name = "kadastr.csv"
csv_out_file = open(out_file_name, "a+")

def download(url, file_name):
    print("%s %s скачиваю" % (url, file_name))
    final_url = "%s%s" % (base_url, urlencode(dict(public_key = url)))
    responce = requests.get(final_url)
    del(final_url)
    download_url = responce.json()["href"]
    del(responce)
    download_response = requests.get(download_url)
    with open(file_name, 'wb') as f:
        f.write(download_response.content)
        f.close()
        del(f)
    del(download_response)

def do_zip(file_name):
    if zipfile.is_zipfile(file_name):
        with zipfile.ZipFile(file_name, "r") as zarc:
            for file_info in zarc.infolist():
                if file_info.filename.find(".ods") > -1:
                    stream = zarc.open(file_info, "r").read()
                    ods_work(stream, file_name)
                    del(stream)
                del(file_info)
            zarc.close()
            del(zarc)

def ods_work(stream, file_name):
    global ods_out_file
    ods_book = pe.get_book(file_type = "ods", file_content = stream)
    lines = len(ods_book[0])
    row = 0
    for rows in ods_book[0]:
        row += 1
        print("Строка %d/%d" % (row, lines), end = "\r")
        if str(rows[2]).find(":") > -1:
            csv_out_file.write("'%s','%s'\n" % (rows[2], file_name))
        del(rows)
    del(ods_book)
    del(stream)

lists = []

for link in soup.find_all("a"):
    disk_url = link.get("href")
    if disk_url.find("https://disk.yandex.ru/d/") > -1:
        zip_file = link.text.replace("/", "_") + ".zip"
        lists.append([disk_url, zip_file])
    del(disk_url)
    del(link)
del(soup)


def work():
    global renew_file, only_one, csv_out_file, lists
    if len(sys.argv) < 2:
        if renew_file:
            csv_out_file = open(out_file_name, "w")
            csv_out_file.write("'Кадастровый номер','Файл с кадастровым номером'\n")
        else:
            csv_out_file = open(out_file_name, "a+")
        for item in lists:
            if not os.path.exists(item[1]):
                download(item[0], item[1])
                if only_one:
                    do_zip(item[1])
                else:
                    cmd = "%s '%s'" % (sys.argv[0],item[1])
                    res = os.system(cmd)
                    del(res)
            else:
                print(item[0], item[1])
            if renew_file:
                if only_one:
                    do_zip(item[1])
                else:
                    cmd = "%s '%s'" % (sys.argv[0],item[1])
                    res = os.system(cmd)
                    del(res)
            del(item)
        csv_out_file.close()
        del(csv_out_file)
        del(lists)
    else:
        csv_out_file = open(out_file_name, "a+")
        for item in sys.argv[1:]:
            do_zip(item)
        csv_out_file.close()
        del(csv_out_file)

if __name__ == "__main__":
    work()

Скачивание всех файлов не вызывает утечки, а утечка возникает именно при обработке каждого zip архива и обработке сохранённого в нём ods файла.
Если изменить переменную на
only_one = False
то утечка не происходит, так как вызывается обработка каждого zip архива отдельным процессом.
  • Вопрос задан
  • 51 просмотр
Пригласить эксперта
Ответы на вопрос 1
@DimkaI Автор вопроса
Системный адинистратор, разработчик ПО
Часть строк профайлера хоть с какими-то значимыми данными
spoiler
Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     43/1    0.000    0.000  817.188  817.188 :0(exec)
  5484818   20.692    0.000   46.853    0.000 :0(iter)
  5485353   10.412    0.000   10.412    0.000 :0(join)
      506    0.001    0.000    0.001    0.000 :0(keys)
914595/914421    1.762    0.000    1.763    0.000 :0(len)
   446645    7.550    0.000    7.550    0.000 :0(print)
   921434   15.975    0.000  130.259    0.000 :0(sum)
        1    0.000    0.000  817.188  817.188 <string>:1(<module>)
  9605836   36.841    0.000   36.841    0.000 base.py:106(get_attr)
  7316831   11.915    0.000   11.915    0.000 base.py:20(__init__)
  5484988   26.161    0.000   26.161    0.000 base.py:26(__iter__)
  2742494    4.734    0.000    4.734    0.000 base.py:46(kind)
  2742154   22.981    0.000  210.510    0.000 cells.py:192(plaintext)
  2742154   28.185    0.000  159.323    0.000 cells.py:193(<listcomp>)
  3661017   18.466    0.000   24.486    0.000 cells.py:47(__init__)
  8693111   50.408    0.000   98.905    0.000 cells.py:57(value_type)
  5032094   27.218    0.000  294.807    0.000 cells.py:61(value)
   533047    1.942    0.000    1.942    0.000 cells.py:63(convert)
       85    0.002    0.000  798.238    9.391 core.py:29(get_book_stream)
       85    0.002    0.000  800.455    9.417 core.py:42(get_book)
       85    0.001    0.000  798.195    9.391 excel.py:26(parse_file_content)
       85    0.001    0.000  798.194    9.391 excel.py:31(_parse_any)
       85    0.876    0.010  798.187    9.390 io.py:146(load_data)
       85    0.001    0.000  798.193    9.391 io.py:58(get_data)
       85    0.002    0.000  798.193    9.391 io.py:92(_get_data)
       85    0.008    0.000  817.176    9.614 kadastr.py:51(do_zip)
       85    5.751    0.068  816.894    9.611 kadastr.py:63(ods_work)
        1    0.001    0.001  817.188  817.188 kadastr.py:89(work)
       85    0.001    0.000  798.195    9.391 memory_input.py:34(get_data)
  4118644   21.190    0.000  507.381    0.000 odsr.py:30(column_iterator)
  3661017   42.407    0.000  481.897    0.000 odsr.py:37(cell_value)
       85    0.002    0.000  229.133    2.696 odsr.py:63(__init__)
       85    0.001    0.000  221.581    2.607 odsr.py:66(<listcomp>)
       85    0.001    0.000  229.134    2.696 odsr.py:84(__init__)
      170    0.001    0.000  221.577    1.303 pagecontainer.py:23(<genexpr>)
        1    0.000    0.000  817.197  817.197 profile:0(kadastr.work())
  4118644   12.905    0.000  520.286    0.000 reader.py:125(column_iterator)
       85    0.002    0.000  229.176    2.696 reader.py:52(open_content)
   457712   32.921    0.000  568.112    0.001 sheet.py:53(to_array)
  3661017   22.863    0.000   96.874    0.000 table.py:108(get_cell)
       85    0.002    0.000  221.573    2.607 table.py:30(__init__)
       85    0.002    0.000  221.570    2.607 table.py:31(init_attributes_by_xmlnode)
       85    0.169    0.002   81.680    0.961 tablenormalizer.py:121(expand_repeated_table_content)
       85    0.003    0.000  138.726    1.632 tablenormalizer.py:137(align_table_columns)
       85    1.119    0.013   70.381    0.828 tablenormalizer.py:142(_align_table_columns)
       85    0.005    0.000  220.411    2.593 tablenormalizer.py:152(normalize_table)
   460717   14.005    0.000   71.672    0.000 tablenormalizer.py:39(expand_cells)
       85    2.420    0.028   80.858    0.951 tablenormalizer.py:50(normalize)
  3680721   22.298    0.000   57.667    0.000 tablenormalizer.py:91(expand_cell)
       85    0.002    0.000  220.914    2.599 tablerowcontroller.py:17(__init__)
   457628    1.594    0.000    2.579    0.000 tablerowcontroller.py:32(ncols)
  3661017   18.287    0.000   24.466    0.000 tablerowcontroller.py:38(get_cell)
  3661017    6.179    0.000    6.179    0.000 tablerowcontroller.py:46(_adjust_negative_indices)
        1    0.000    0.000    0.000    0.000 tablerowcontroller.py:63(TableRowController)
       85    0.001    0.000  220.914    2.599 tablerowcontroller.py:64(__init__)
        1    0.000    0.000    0.002    0.002 tablerowcontroller.py:7(<module>)
       85    0.002    0.000   68.342    0.804 tableutils.py:58(get_min_max_cell_count)
       85    1.072    0.013   67.846    0.798 tableutils.py:59(<listcomp>)
      340    2.167    0.006    2.168    0.006 tableutils.py:65(get_table_rows)
   921434    5.217    0.000  135.476    0.000 tableutils.py:68(count_cells_in_row)
  8290526   50.406    0.000  114.284    0.000 tableutils.py:69(<genexpr>)
 11511210   15.884    0.000   15.884    0.000 tableutils.py:81(__init__)
 11050493   60.123    0.000   80.124    0.000 tableutils.py:84(cols)
   460717    2.536    0.000    3.364    0.000 tableutils.py:89(rows)
   461907    2.797    0.000    3.647    0.000 tableutils.py:94(cols)
  2742664   13.829    0.000   18.279    0.000 text.py:24(__init__)
2742664/2742494   33.405    0.000   90.295    0.000 text.py:41(plaintext)
   912640    5.406    0.000   10.239    0.000 whitespaces.py:43(count)
   912640    3.371    0.000   13.610    0.000 whitespaces.py:56(plaintext)
       85    0.001    0.000  221.576    2.607 wrapcache.py:16(wrap)
 21584297   38.183    0.000   38.184    0.000 xmlns.py:38(_prefix2clark_cached)
317341/7317171   48.206    0.000  318.789    0.000 xmlns.py:87(wrap)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы