Самый эффективный способ хранения очень большого 2D-массива в Python / MicroPython - PullRequest
2 голосов
/ 31 марта 2020

У меня есть проект во встроенной системе (NodeMCU под управлением Micro Python), где мне нужно хранить очень большой массив переменных со значениями 0 или 1. Мне нужно иметь возможность читать / писать их по отдельности или через петли в удобной форме. В этом примере я заполняю массив случайными целыми числами от 0 до 1:

N = 50
table = [[randInt(0,1) for i in range(N)] for j in range(N)]

На моем NodeMCU даже такого небольшого массива (2500 элементов) достаточно, чтобы превысить пределы памяти NodeMCU, что приводит к сбою моего скрипт. Я полагаю, это потому, что в Python int - это объект с большими накладными расходами. Поскольку в моем случае мне не нужна емкость переменной int - фактически, 0 или 1 могут быть сохранены как биты - как я могу создать и заполнить массив переменными с наименьшим объемом памяти? Скажем, как в этом примере, рандомизация между 0 и 1. Я просмотрел uctypes , но, поскольку я новичок в Python, я не смог заставить их работать. Или есть другой способ? Как создать такой массив с наименьшим использованием памяти?

1 Ответ

0 голосов
/ 31 марта 2020

Вы правы, что int объекты имеют много накладных расходов. Однако в этом случае эти int объекты могут фактически быть кэшированы (в CPython они будут), поэтому единственные издержки должны быть только указателем ...

Однако для указателя все равно потребуется машинное слово, чтобы не полагаться на такие вещи (подробности реализации) и упаковать вещи более плотно, вы можете использовать фактические массивы , в настоящее время вы используете list из list объектов.

Модуль arrays предоставляет объектно-ориентированные оболочки вокруг примитивных, C -подобных числовых c массивов. К сожалению, они не предоставляют многомерных массивов.

Так что вы можете попробовать что-то вроде:

import array
import random

N = 50

def build_table(N):
    rng = range(N)
    result = []
    for _ in rng:
        arr = array.array('B') #unsigned byte
        for _ in rng:
            arr.append(random.randint(0,1))
        result.append(arr)
    return result

table = build_table(N)

Если бы это было CPython, я бы предложил bitarray* модуль 1021 * для максимальной эффективности. Я понятия не имею, доступно ли это для микро python, но вы могли бы реализовать что-то подобное самостоятельно, вероятно, поверх array.array. Есть много примеров этого, это своего рода классическая структура данных c со времен, когда память измерялась в байтах. Вот только один пример из Python вики.

...