Я делаю проект для класса, который фокусируется на хранении огромной матрицы с почти 0 значениями в памяти и выполнении некоторой математической математики для нее. Моей первой мыслью было использовать HashMap
для хранения элементов матрицы и хранить только ненулевые элементы, чтобы избежать использования огромных объемов памяти.
Я хотел создать ключ для HashMap
, который бы представлял номер строки и столбца элемента таким образом, чтобы при доступе к этой записи на карте я мог повторно извлечь оба значения. Я не знаю Java так же хорошо, как C # - в C # я бы сделал struct
с Row
и Column
членами, но в Java я быстро понял, что типов пользовательских значений нет. С приближением крайнего срока я сделал безопасную ставку и сделал Key
длинной. Я сохранил данные строки (32-битное целое) в первых 32 битах и данные столбца в последних 32, используя очень простое смещение битов. [РЕДАКТИРОВАТЬ: Я также хотел бы отметить, что мой HashMap инициализируется с определенным начальным размером, который точно представляет количество значений, которые я храню в нем, и никогда не превышается.]
[Примечание: причина, по которой я хочу иметь возможность снова извлекать данные строки / столбца, заключается в значительном увеличении эффективности умножения матриц, с O(n^2)
до O(n)
и меньшего n
для загрузки]
Что я заметил после реализации этой структуры, так это то, что для считывания матрицы 23426 x 23426 из текстового файла, в котором заданы только ненулевые элементы, требуется колоссальные 7 секунд, но для вычисления собственных значений требуется всего 2 секунды. мы обязаны дать! После выборочного комментирования методов я пришел к выводу, что большая часть этого 7-секундного промежутка времени расходуется на сохранение моих значений в HashMap
.
public void Set(double value, int row, int column) {
//assemble the long key, placing row and column in adjacent sets of bits
long key = (long)row << SIZE_BIT_MAX; //(SIZE_BIT_MAX is 32)
key += column;
elements.put(key, value);
}
Это код для установки значения. Если я использую этот метод вместо:
public void Set(double value, int row, int column) {
//create a distinct but smaller key (around 32 bits max)
long key = (long)(row * matrixSize) + column;
elements.put(key, value);
}
Чтение занимает всего 2 секунды. Обе эти версии ключа различны для каждого элемента, оба имеют длинный тип, и фактический код для создания любого из них имеет минимальную сложность. Это elements.put(key, value)
, который составляет разницу между 7 секундами и 2.
Мой вопрос: почему? Различие, которое я вижу между этими ключевыми версиями, состоит в том, что первая имеет биты, установленные на 1 повсюду и чаще, в то время как вторая имеет все свои старшие 32 бита, установленные на 0. Я гоняюсь за красной сельдью, или это довольно существенная разница? в производительности результат чего-то внутреннего в методе HashMap.put
?