Вектор обнуляемых HashMaps в ржавчине

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

Самое главное, я хочу свести к минимуму время доступа и модификации, включая амортизированные распределения. Затем я хочу максимально сократить использование памяти без увеличения времени доступа или, по крайней мере, незначительно.

О времени выполнения: я определенно буду много искать, поэтому мне нужно наилучшее возможное время доступа, которое будет дано вектором, а не HashMap<(INDEX, KEY), Value>, как указано в комментариях. Поправьте меня, если я ошибаюсь: хеширование и обработка коллизий определенно повлияют на производительность. Мой ключ представляет собой сложную структуру. Хотя я подумываю упростить его в перечислении для ключа, поэтому, возможно, в этом случае хэширование будет дешевле, но я не уверен, что это будет возможно.

О памяти: мне нужно избежать ненужных накладных расходов на память с пустым HashMap, для которого требуется 48 байтов в памяти. Мой вектор имеет размер порядка 100 миллионов, поэтому он может легко потреблять десятки ГБ. Чтобы выйти из этой расточительной ситуации, я решил использовать Option<Box>. Насколько я понимаю, мне требуется обнуляемость, и я не могу использовать Box напрямую в этом случае, потому что этот тип не допускает обнуляемости, следовательно, это заставит меня использовать пустой HashMap и зарезервировать 48 байтов где-то в памяти плюс дополнительные 8 байтов на элемент из-за сама коробка. С Option<Box> вариант None потребляет всего 8 байтов, что приводит к уменьшению памяти до 6 раз, если все элементы были пустыми хэш-картами.

Я очень открыт для альтернативных подходов к реализации разреженных матриц, которые удовлетворяют мои потребности, но в этом вопросе я хочу сосредоточиться на шаблонах ржавчины для эффективных с памятью представлений вектора хэш-карт, которые также избегают иметь дело с тем, что кажется мне излишне многословными цепочками Типы опций и указателей (Box/Rc и др.). Есть ли лучший подход для обработки векторов обнуляемых HashMaps в ржавчине?

Я ничего не понимаю в ваших жалобах. Было бы короче объяснить, что вы пытаетесь сделать, вместо того, чтобы говорить о решении, которое, по вашему мнению, вам нужно.

Stargateur 15.04.2023 17:55

@Stargateur добавил больше деталей

Redirectk 15.04.2023 19:53

Я прочитал весь ваш вопрос и не понял, в чем проблема. Вам было сложно работать с Vec<Option<Box<HashMap<K, V>>>> или вы где-то застряли? (Если да, укажите где.) Или вы просто находите цепочку дженериков слишком уродливой и задаетесь вопросом, есть ли лучший способ? (Если это так, пожалуйста, не пугайтесь цепочки - просто прочитайте это как «вектор необязательного принадлежащего указателя на хэш-карту».) То, что вы описали, кажется мне совершенно разумным и идиоматичным. Rust предоставляет такие типы, как Option и Box, именно поэтому вы можете оптимизировать, как вы планируете сделать здесь. Действуй.

user4815162342 15.04.2023 21:51

@user4815162342 user4815162342 да, действительно, я нахожу это многословным и шаблонным, и мне интересно, есть ли лучший способ (то есть вообще избегать цепочки) или мне просто нужно привыкнуть к этому :)

Redirectk 15.04.2023 22:11

@Redirectk Я, наверное, повторяюсь в этот момент, но чтобы все было ясно на 100%, я думаю, вам следует привыкнуть к этому, и я даже не вижу, где находится шаблон. Альтернативой является переход на подход с одной хэш-картой, который кажется лучшим выбором для разреженного поиска и приведет к меньшему количеству распределений. В любом случае, если у вас есть конкретная проблема с чем-то необоснованно сложным или многословным, задайте более конкретный вопрос. В остальном, я думаю, это отличный способ изучить Rust (я предполагаю, что вы новичок в этом языке) — получайте удовольствие!

user4815162342 15.04.2023 22:15

Я думаю, что @user4815162342 и @Ahmed Masud правы в том, что использование одного HashMap является правильным подходом, если только у вас нет каких-то действительно загадочных требований. Если вы действительно хотите использовать Vec<Option<Box<HashMap<K, V>>>, вы можете обернуть его в пользовательский тип и реализовать методы для этого типа, которые уменьшают многословность, например. fn insert(&mut self /* CustomType */, usize i, K k, V v) -> Option<V> { /* insert into position i of the Vec, creating a new HashMap if it is None */ }.

willtunnels 16.04.2023 01:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Согласно документации Rust, создание пустого HashMap не приводит к выделению кучи. На самом деле контейнеры Rust в целом имеют такое поведение. Не нужно заворачивать HashMap в Option.

Тот факт, что обнуляемость должна быть явно выражена в Rust, заключается в том, чтобы гарантировать, что контракты API понятны как для автора библиотеки, так и для пользователя. Как и во всем, «бесплатных обедов не бывает», и для того, чтобы сделать это явным, может потребоваться несколько unwraps здесь и там.

Наконец, обратите внимание, что хотя HashMap не является Copy, но является Clone, если его ключи, значения и состояние равны Clone (фактически состояние по умолчанию — клонирование). Как указано в документации Rust, Clone «[d] отличается от Copy тем, что Copy является неявной и недорогой побитовой копией, в то время как Clone всегда является явным и может быть или не быть дорогим».

Для пустой HashMap по-прежнему требуется 48 байтов в соответствии с size_of, а для опции требуется только 8. Наличие миллионов пустых хэш-карт в векторе легко заставляет мою программу потреблять десятки ГБ.

Redirectk 15.04.2023 17:19

@Redirectk Просто чтобы не запутать других читателей, вы, вероятно, очень свободно используете термин «опция» для обозначения Option<Box<HashMap<K, V>>> или аналогичной косвенности, потому что Option<HashMap<K, V>> требует точно такого же объема памяти. как HashMap<K, V>

cafce25 15.04.2023 17:50

@ cafce25 вы правы, но вы забыли опцию в типе XD

Stargateur 15.04.2023 17:57

@cafce25 совершенно прав. Если бы вы хотели избежать 48 байтов, вы бы использовали Box. Это ортогонально тому, используете ли вы Option. Я понимаю путаницу, потому что большинство языков объединяют обнуляемость со стратегией распределения (например, Java).

willtunnels 15.04.2023 17:58

@Redirectk, если вам нужны миллионы HashMaps в векторе, возможно, вам нужно переписать собственный контейнер. Например, рассматривали ли вы хэш-карту, имеющую форму HashMap<(INDEX, KEY), Value>, для замены всего вашего вектора хэш-карт, где INDEX — позиция в этом большом векторе, а KEY — локальный ключ хэш-карты? Когда вы начинаете сталкиваться с такими большими структурами, вам приходится создавать собственную структуру данных, чтобы оптимизировать ситуацию, потому что вы знаете о ней больше, чем общие реализации.

Ahmed Masud 15.04.2023 17:58

@ cafce25 Это справедливое замечание. Я уточню свой вопрос, что я имею в виду Option<Box<T>> или аналогичные цепочки типов/опций указателя.

Redirectk 15.04.2023 19:49

@willtunnels Мне кажется, что для создания Box<HashMap<...>> по-прежнему требуется пустой HashMap в памяти? Плюс дополнительные 8 байт для самой коробки

Redirectk 15.04.2023 19:49

@AhmedMasud Это действительная альтернатива. Я отредактировал свой вопрос, чтобы уточнить, что в моем случае время доступа действительно важно, и поиск карты, вероятно, будет слишком медленным. Я не запускал никаких тестов в этом случае, поэтому, пожалуйста, поправьте меня, если я ошибаюсь!

Redirectk 15.04.2023 19:50

@Redirectk, только эталонный тест может дать вам окончательный ответ, но помните, что поиск HashMap - это O (1), поэтому поиск в одном унифицированном HashMap должен быть быстрее, чем поиск HashMap в Vec с последующим поиском ключа в этом меньшем HashMap. Конечно, это предполагает, что вам не нужно перебирать все элементы HashMap числа n.

Jmb 15.04.2023 20:34

@Redirectk Ах да, это очевидно правда.

willtunnels 16.04.2023 01:03

Другие вопросы по теме