Уменьшить потребление памяти

Рейтинг: 1Ответов: 1Опубликовано: 02.02.2023

Всем привет, написал генератор с асинхронными запросами для парсинга, но из-за большого количество запросов, код кушает много ОЗУ, 12гб (На машине 16гб), задался вопросом, код работает быстрее requests но жертвуя ОЗУ. Можно ли без потери скорости, оптимизировать код, но с меньшими потреблениями ресурсов ?!

import grequests

numbers = ["https://exampkesite.com/api/info?product=2501{:0000007}".format(x) for x in range(100000000)]

response = (grequests.get(num) for num in numbers)

resp = grequests.map(response)

Ответы

▲ 6Принят
numbers = ["https://exampkesite.com/api/info?product=2501{:0000007}".format(x)
           for x in range(100000000)]

Вот эта строка одна забивает память на порядка 100000000 * 52 * 2 байт ~= 9 гигабайт (52 - длина каждого url после подстановки числа, 2 - размер каждого символа (wchar_t) в байтах). Замените списковое выражение на генератор (замените квадратные строки на круглые), чтобы адреса генерировались по мере необходимости, а не сразу все.

Также можно разбить весь объем на блоки по 10000 или 1000 адресов, отправлять запросы блоками, результаты не хранить в памяти, а сохранять сразу на диск. Либо получать, обрабатывать, и сразу сохранять, но в любом случае не хранить все промежуточные или итоговые результаты в памяти.

Оптимальный размер блоков определите экспериментально: небольшие блоки будут меньше забивать вам память, при очень маленьких блоках будет обрабатываться меньше запросов за раз, чем могло бы.

Насколько я вижу по примеру в readme репозитория grequests, это можно реализовать через grequests.imap, что-то вроде этого:

import grequests

urls = ("https://exampkesite.com/api/info?product=2501{:07}".format(x)
        for x in range(100000000))

reqs = (grequests.get(num) for url in urls)

with open("results.txt", "w") as file:
    for resp in grequests.imap(reqs, size=1000):
        print(resp.url, resp.text, file=file)

Я бы попробовал сначала size вообще не ставить, потом попробовать ставить 10, 100 и выше.

grequests.imap кстати тоже позволяет экономить память - в отличие от grequests.map он не собирает все результаты в список (на вашей задаче он будет огромным), а возвращает их по мере получения, и вы можете их последовательно обрабатывать (или просто сохранять в файл для последующей обработки, как в моем пример).