LINUX.ORG.RU

Новая структура данных Black-White Array

 


0

2

https://habr.com/ru/articles/984184/

Github

Преимущества

  • Амортизированное время вставки/удаления/поиска O(\log N) - сравнимое с BTree от Google;
  • Количество аллокаций памяти при операциях вставки так же O(\log N) - меньше давления на сборщик мусора, ниже фрагментация памяти;
  • Массивы под капотом: данные лежат рядом, что улучшает кэшируемость процессором и скорость обхода/доступа к данным;
  • Позволяет хранить элементы с одинаковыми ключами - не нужно использовать дополнительные структуры для группировки таких элементов;
  • Низкий оверхед на хранение служебной информации - экономия памяти по сравнению с другими структурами данных;
  • Удобен для вставки батчами;
  • Простая сериализация и десериализация;

Компромиссы

  • Время вставки варьируется от O(1) - каждая вторая вставка, до O(N) - один раз на N операций, но амортизированное время O(\log N). Для near-real-time систем это может быть критично. Эффект может быть нивелирован вставкой батчами, или асинхронной вставкой в фоне.

  • При редких паттернах операций массового удаления, возможна деградация производительности поиска до O(N)/4. Эффект может быть предотвращен вызовом метода Compact().

Пора делать новую ФС на новом принципе.

Перемещено Pinkbyte из talks

★★★★★

Последнее исправление: ptah_alexs (всего исправлений: 1)
Ответ на: комментарий от Ygor

Если ты про негров то их нельзя называть именно неграми, а вот черными можно.

blacklist/whitelist всякие комитеты по этосамому рекомендуют заменять на blocklist/allowlist

нельзя называть именно неграми

Наш «негр» переводится negro, а нельзя nigger

goingUp ★★★★★
()

сравнимое с BTree от Google

Что за гуглофанатизм? btree никаким боком не от гугла,

И вообще, чем описанное отличается от btree по характеристикам? По ссылке не ходил.

Сдаётся мне что там никакая не новая структура а чья-то очередная курсовая работа по реализации какого-то баяна.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Простая сериализация и десериализация;

Не раскрыто, и заголовков струтур не видно при прочтении по-диагонали. Мне кажется это могло бы быть ключевой фишкой, типа zero-copy передача kv по всяким shared memory между процессами так, чтобы формат данных описывался как стандарт просто, без привязки к алгоритму.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 3)
Ответ на: комментарий от firkax

Ну вообще хорошо бы расписать хотя бы общий принцип, а не только алгоритмическую сложность операций. Да и структура данных не шибко новая - исследование ещё в 2020 вышло.

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

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

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

Ты, почти как автор темы, опустил самое важное.

Напишу тогда свой пересказ:

=== описание хранения данных ===

Экземпляр описываемой «структуры» как цельный объект (т.е. всё ниженаписанное - описание внутреннего устройства одного экземпляра) буду называть bwarr.

Данные хранятся массиве, нарезанном на фрагменты, размер каждого из которых равен pow(2,n), где n - номер фрагмента, нумерация начинается с нуля. Запишем так: frag[n] - n-ный фрагмент, frag[n][m] - m-ый элемент n-го фрагмента, при этом n>=0, 0<=m<pow(2,n). Если нужна поддержка операции удаления, то frag[n][m] должен уметь хранить как элемент, так и признак «тут ничего нет». Если не нужна, то признак пустоты нужен только фрагментам целиком, но не отдельным их элементам.

Консистентное состояние данных выглядит так: каждый из фрагментов, независимо от остальных, хранит отсортированное подмножество ранее добавленных в bwarr элементов. Чем больше номер фрагмента - тем более старые элементы в нём хранятся, то есть фрагменты, можно считать, отсортированы по времени добавления содержащихся в них элементов, но при этом сами элементы внутри одного фрагмента отсортированы по требуемому сортирующему признаку. Фрагмент может быть либо пустым (в нём нет ни одного элемента), либо содержать k элементов такое, что pow(2,n-1)<k<=pow(2,n). То есть, любой непустой фрагмент всегда заполнен более чем наполовину. Таким образом, если в bwarr ровно N=pow(2,X) элементов (X=log_2(N)), то они либо все хранятся в frag[X], либо часть из них (все не влезут) хранится в более нижних фрагментах (причём не все варианты расположения возможны). Если элементов меньше чем pow(2,X) то фрагменты с номерами больше X всё так же не могут быть непустыми.

=== описание операции поиска ===

Поиск ведётся параллельно во всех непустых фрагментах. Поскольку максимальный номер непустого фрагмента зависит от общего количества элементов N, параллельно искать придётся не более чем в ceil(log_2(N))+1 = X+1 фрагментах. Сам поиск по заранее отсортированным фрагментам делается за логарифмическое от их размера pow(2,n) (и соответственно линейное от их номера n) количество операций. Если сложить эту арифметическую прогрессию, получаем сложность поиска приблизительно пропорциональную sqr(X) = sqr(log_2(N)).

=== описание операций изменения данных ===

Для вставки и иногда для удаления используется временный буфер (почему-то там его назвали чёрным массивом), требуемый размер этого буфера равен размеру последнего из разрешённых/планируемых к использованию фрагментов (если не нужно удаление, размер временного буфера можно сделать меньше на 25%).

Вставка делается так: если frag[0] пустой, просто кладём элемент в него и завершаемся, иначе кладём вставляемый элемент во временный буфер, ставим счётчик i=0, и затем выполняем в цикле следующее:

  • Делаем отсортированное слияние frag[i] и временного буфера. frag[i] после этого объявляем пустым (все элементы из него переехали в слияние). При этом, если frag[i+1] пустой, результат пишется в него и завершаемся. Иначе - результат пишется во временный буфер, счётчик i инкрементируется, идём на следующий цикл.

Стоит обратить внимание, что указанный алгоритм никогда не приведёт к необходимости слияния последнего фрагмента с чем бы то ни было, если не превышать допустимое для bwarr полное количество элементов, указанное выше. То есть если происходит слияние предпоследнего - то последний гарантированно пустой и временный буфер для результата нам тут не потребуется.

Удаление делается так: элемент (после поиска) просто помечается как пустой. Затем делается проверка: если в фрагмент до сих пор заполнен больше чем на половину (т.е. пустых мест меньше половины) - завершаемся. Если пустых мест теперь половина, а предыдущий фрагмент пустой - переносим элементы туда. Если пустых мест половина, а предыдущий фрагмент не пустой - производим сортированное слияние с ним (через временный буфер), после чего записываем результат на место текущего фрагмента (а предыдущий, из которого мы забрали элементы, объявляем пустым).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 3)
Ответ на: комментарий от Bfgeshka

иметь чёрный массив емкостью в половину основного белого и использовать его для выполнения операций

Белый использует чёрного для выполнения работы, ЧТД.

Nervous ★★★★★
()

Структура данных не поддерживает операции «следующий» (в порядке сортировки) и «предыдущий», поэтому её можно заменить хэш-таблицей. Будет быстрее. По памяти — тоже можно лучше (sparse_hash_map (вот это действительно от Google) имеет оверхед в 4 бита на элемент).

Амортизированное время вставки/удаления/поиска O(\log N)

Это враньё. Для поиска нет никакого амортизированного времени, потому что искать можно либо один и тот же, либо разные, элементы. Если искать один и тот же, то время на M поисков в худшем случае будет O(M (\log N)^2).

Для удаления нужно сначала найти, т.е. тоже O((\log N)^2). Можно возразить, что, мол, один раз удалённый нельзя ещё раз удалить, но дело в том, что там есть элементы (не один элемент!), которые искать сложнее, чем за логарифм. Если в нужном порядке удалять такие элементы, мы снова получаем O(M (\log N)^2) на M удалений в худшем случае.

Если используется как set, а не multiset, то для вставки тоже нужно сначала найти (чтобы не вставить вторую копию).

Прибавьте к этому постоянные затыки у branch predictor’а и prefetcher'а с бинарным поиском.

Массивы под капотом: данные лежат рядом, что улучшает кэшируемость процессором и скорость обхода/доступа к данным

Так ты ж по ним бинарный поиск делаешь, дядя! Какая кэшируемость? Какая скорость обхода/доступа?

---

Зачем оно нужно? Оно хуже, чем хэш-таблица, оно хуже, чем RB trees, AVL trees, B-trees, и так далее. И в теории, и на практике.

shdown
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от Nervous

Всё ещё хуже: никаких оснований называть массивы именно так не было, там действительно есть массив с данными и временный массив для слияний, они совершенно не аналогичны друг другу и называние их просто цветами только запутывает. Наилучшее название для второго - tmp.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от Bfgeshka

Да и структура данных не шибко новая - исследование ещё в 2020 вышло.

Об авторе оригинальной публикации

Идея BWA принадлежит профессору Йельского университета Джорджу Моу (Z. George Mou), я отправил ему реализацию BWA на Go, и он её одобрил. Сейчас профессор Моу работает над публикацией алгоритма пространственного поиска и его открытой реализации на C++.

его открытой реализации на C++.

Подожду её. :)

dataman ★★★★★
()
Ответ на: комментарий от Ygor

Тю. Ты много пропустил. Там забороли все: master, slave, blacklist, whitelist, white hat, black hat, dummy, sanity check, man in the middle. Шутку про abort из libc удалили.

Мудрый народ давно этот феномен описал: пусти свинью под стол она вылезет на стол.

urxvt ★★★★★
()

Этой «новой» структуре уже 6 лет. Нехило так хабр отстаёт от жизни. Вот это более-менее новое, но я не проверял насколько оно полезно и есть ли ошибки. Вообще если по этому ресурсу покопаться, то можно найти и то, что появилось на свет вчера. Короче я ХЗ. Вроде и полезная штука, а вроде уже и легаси. Ребёнок за это время уже в школу мог успеть пойти от рождения.

peregrine ★★★★★
()
Ответ на: комментарий от question4

Думаю, если представить такую ситуацию: разговривает в штатах местный негр с нашим человеком через переводчика и наш человек скажет в своей русской речи «переведи этому негру, что …», то этому самому негру будет неинтересно, что это была русская речь…

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)