Загрузка продуктов через API в recursion сохранение в Postgres -> каждая рекурсия потребляет больше оперативной памяти. Как очистить оперативную память после рекурсии?

#python-3.x #postgresql #recursion #python-requests #psycopg2

#python-3.x #postgresql #рекурсия #python-запросы #psycopg2

Вопрос:

Мне нужно загрузить 400 тыс. записей через API и сохранить их локально в БД. Каждый запрос возвращает 500 записей курсор для следующей страницы. Я использую рекурсию и вижу, что python3 каждый процесс рекурсии потребляет больше оперативной памяти (около 50 МБ на рекурсию, поэтому мне нужно иметь 40 ГБ оперативной памяти для загрузки всего). Каков способ очистки оперативной памяти после каждой рекурсии?

 import os
import psycopg2
import requests

from psycopg2.extras import execute_values


class SomeClass:
    def __init__:
        with psycopg2.connect(
            host='localhost',
            dbname=os.getenv("POSTGRES_DBNAME"),
            user=os.getenv("POSTGRES_USER"),
            password=os.getenv("POSTGRES_PASSWORD")
        ) as self.conn:
            self.products_download_n_save()

    def products_download_n_save(self, cursor=''):
        basic_url = 'SOME_URL'

        if not cursor:
            url = basic_url
        else:
            url = f'{basic_url}?cursor={cursor}'

        r = requests.get(url)
        response = r.json()
        products = response['products']

        # Need to loop every product, because different product have different amount of fields 
        for product_d in products:
            values = [[value for value in product_d.values()]]

            columns = product_d.keys()
            do_update_query = ','.join([f'{column} = excluded.{column}' for column in columns])

            query = f"INSERT INTO {self.PRODUCTS_TABLE_NAME} ({','.join(columns)}) VALUES %s " 
                    f"on conflict(productCode) " 
                    f"DO UPDATE SET {do_update_query};"

            with self.conn.cursor() as cursor:
                execute_values(cursor, query, values)

        self.conn.commit()

        response_cursor = response.get('nextCursor', '')

        if response_cursor:
            self.products_download_n_save(response_cursor)
 

Ответ №1:

Найдено решение — переместить код из рекурсии в while response_cursor цикл.