2015-07-04 2 views
5

Мне нужно создать массив с 3 миллиардами булевых переменных. Моя память составляет всего 4 ГБ, поэтому мне нужно, чтобы этот массив был очень плотным (не более одного байта на переменную). Теоретически это должно быть возможно. Но я обнаружил, что Ruby использует слишком много места для одной логической переменной в массиве.Есть ли более легкая альтернатива массиву?

ObjectSpace.memsize_of(Array.new(100, false)) #=> 840 

Это более 8 байт на переменную. Я хотел бы знать, есть ли более легкая реализация C-массивов в Ruby.

Помимо небольшого профиля, мне также нужен каждый булев этот массив, чтобы быть быстрым, потому что мне нужно как можно быстрее перевернуть их по требованию.

+4

Использование растровых изображений. Имейте одну строку и просто переверните отдельные ее биты. Нет накладных расходов массива, 8 значений на байт. Круто, да? :) –

+1

Почему вы просто не храните свои биты в целых числах? –

+3

['NArray.byte'] (https://masa16.github.io/narray/) – cremno

ответ

0

Ruby не очень хорошо работает, особенно в использовании памяти. Как и другие, вы должны поместить свои логические числа в числа. Вы потеряете много памяти из-за "objetification" Рубина. Если это плохой сценарий для вас, вы можете хранить в строках большой длины и хранить строки в массиве, теряя меньше памяти.

http://calleerlandsson.com/2014/02/06/rubys-bitwise-operators/

Вы также можете реализовать свой собственный драгоценный камень в C++, которые могут естественным образом использовать биты и двойники, теряя меньше памяти. И массив удвоений означает 64 булевых элемента в каждой позиции, что более чем достаточно для вашего приложения.

Чрезвычайно большие объекты всегда являются проблемой и потребуют от вас многого, чтобы упростить работу с большой коллекцией объектов. Конечно, вам придется хотя бы реализовать какой-то метод, чтобы удержать какую-то позицию в массиве объектов, в котором хранится более одного булева, а другое - для их переворачивания.

0

Следующий класс может отличаться от того, что вы ищете. Он будет хранить 1 или 0 в массив, используя биты и сдвиг. Записи по умолчанию равны 0. Если вам нужно три состояния для каждой записи, 0, 1 или нуль, то вам нужно будет изменить ее, чтобы использовать два бита для каждой записи, а не одну.

class BitArray < Array 
    BITS_PER_WORD = 0.size * 8 
    MASK = eval("0x#{'FF' * (BITS_PER_WORD/8)}") - 1 

    def []=(n, value_0_or_1) 
    word = word_at(n/BITS_PER_WORD) || 0 
    word &= MASK << n % BITS_PER_WORD 
    super(n/BITS_PER_WORD, value_0_or_1 << (n % BITS_PER_WORD) | word) 
    end 
    def [](n) 
    return 0 if word_at(n/BITS_PER_WORD).nil? 
    (super(n/BITS_PER_WORD) >> (n % BITS_PER_WORD)) & 1 
    end 

    def word_at(n) 
    Array.instance_method('[]').bind(self).call(n) 
    end 
end 
Смежные вопросы