Как эффективно смоделировать очередь поверх хранилища ключевых значений?
Предположим, что у меня есть база данных ключ-значение, и мне нужно построить очередь поверх нее. Как я мог бы достичь этого, не получая плохой производительности?
Одна из идей может заключаться в том, чтобы хранить очередь внутри массива и просто хранить массив с помощью фиксированного ключа. Это довольно простая реализация, но очень медленная, так как для каждого доступа чтения или записи полный массив должен быть загружен / сохранен.
Я также могу реализовать связанный список со случайными ключами, и есть один фиксированный ключ который выступает в качестве отправной точки для элемента 1. В зависимости от того, предпочитаю ли я быстрое чтение или быстрый доступ к записи, я могу позволить указать фиксированный элемент на первую или последнюю запись в очереди (поэтому мне приходится перемещать его вперед / назад).
Или, чтобы продолжить это - я мог бы также иметь два фиксированных указателя: один для первого, on для последнего элемента.
Какие-либо другие предложения о том, как сделать это эффективно?
2 ответа:
Я думаю, что это зависит от типа очереди, которую вы хотите реализовать, и никакое решение не будет идеальным, потому что хранилище ключей-значений не является правильной структурой данных для такого рода задач. Там будет всегда какую-то халтуру, участвующих.
Для простой очереди first in first out вы можете использовать несколько магазинов значений кэВ, таких как:
{ oldestIndex:5, newestIndex:10 }
В этом примере в очереди будет 6 элементов (5,6,7,8,9,10). Пункты от 0 до 4 уже выполнены, в то время как пункта 11 или около того пока нет. Рабочий-производитель увеличит newestIndex и сохранит свой товар под ключом
Обратите внимание, что этот подход может привести к проблемам, если у вас есть несколько потребителей/производителей и если очередь никогда не бывает пустой, поэтому вы не можете сбросить индекс.11
. Потребитель берет товар под ключ5
и увеличивает oldestIndex.Но проблема многопоточности также справедлива для связанных списков и т. д.
Изначально структура ключ-значение очень похожа на исходное хранилище памяти, где физический адрес в памяти компьютера играет роль ключа. Таким образом, любой тип структуры данных может быть смоделирован на основе хранения значений ключей, включая связанный список.
Первоначально связанный список - это список узлов, включающий индексную информацию предыдущего узла или следующего узла. Затем узел его собственной, следует также рассматривать как ключ-значение суб структуры. С дополнительным префиксом к ключу, информация в узле может храниться отдельно в плоской таблице пар ключ-значение.
Чтобы продолжить это, специальный суффикс к ключу также может позволить избавиться от избыточной информации указателя. Этот список притворства может выглядеть примерно так:
Я думаю, что соответствующий альгритм также можно себе представить. Если бы у вас был поток демона для манипулирования этими ключами,pilot-last-index: 5 pilot-0: Rei Ayanami pilot-1: Shinji Ikari pilot-2: Soryu Asuka Langley pilot-3: Touji Suzuhara pilot-5: Makinami Mari
pilot-5
можно было бы переименовать вpilot-4
в приведенном выше примере. Даже если, это не позволено иметь дополнительный поток в какой-то особой ситуации на результат очереди он сам не влияет. Просто некоторые накладные расходы будут существовать для точки разрыва в последовательности.Однако, какой из двух вышеперечисленных методов следует применять, является проблемой баланса между стоимостью дискового пространства или накладными расходами процессорного времени.
Потокобезопасность-это именно проблема, однако древняя проблема. Так же, как и класс, реализующий интерфейс
ConcurrentMap
в JDK, атомарная операция над данными ключ-значение также предусмотрена идеально. В некоторых промежуточных программах типа memcached есть аналогичные методы, которые могут заставить вас обновлять ключ или значение отдельно и безопасно для потока. Однако эта реализация является проблемой альгритма, а не ключевой ценностной структуры, которую он сам.