Структура данных libev watchers

Libev использует три структуры данных для хранения разных наблюдателей.

Куча: для наблюдателей, отсортированных по времени, например ev_timer и ev_periodic.

Связанный список: например, ev_io, ev_signal, ev_child и т. д.

Массив: например, ev_prepare, ev_check, ev_async и т. д.

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

Структура данных, в которой хранятся наблюдатели ev_io, кажется немного сложной. Во-первых, это массив с индексом fd, а элемент массива представляет собой связанный список ev_io watcher. Выделить место под массив удобнее, если в качестве элемента использовать связанный список. Это причина?

Или просто из-за того, что операция вставки или удаления ev_io выполняется чаще, а ev_prepare кажется более стабильной?

Или какие-то другие причины?


person changchang    schedule 22.10.2012    source источник


Ответы (2)


Ожидается, что для одного и того же fd (аналогично для сигналов) существует всего несколько (обычно один, и почти всегда максимум два) наблюдателя за вводом-выводом. Помещение ссылок списка в наблюдатель означает, что не требуется никаких дополнительных выделений, как это потребовалось бы, если бы для каждого наблюдателя использовался массив. Если бы на одном и том же fd было активно много наблюдателей за вводом-выводом, то этот подход со связанными списками был бы медленнее.

Массивы используются, потому что вставка и удаление выполняются очень быстро (наблюдатель сохраняет индекс массива). Использование 4-байтового индекса также снижает требования к памяти на 64-битных машинах (12 байтов на наблюдателя по сравнению, например, с 16 для двусвязного списка), а использование массива указателей означает, что все указатели находятся рядом друг с другом в памяти, что повышает эффективность кэширования при сканировании, что является частой операцией для некоторых наблюдателей.

Эффективность кэша также является причиной, по которой 4-куча используется вместо 2-кучи, и причиной, по которой значения времени копируются в структуру данных кучи, чтобы избежать доступа к памяти наблюдателя при операциях с кучей.

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

person Remember Monica    schedule 07.01.2013
comment
Хорошо, я понял. Спасибо, Марк! Еще раз спасибо за создание libev. :) - person changchang; 15.01.2013

Вероятно, причина в том, что в типичном сценарии ev_io нужно искать с помощью fd. Базовая библиотека (epoll, select или что-то еще) предоставит fd с некоторым событием. Затем Либев просто использовал бы его как индекс и просто перебирал бы связанный список наблюдателей за событиями, которые необходимо вызвать. Так что это может быть быстро в огневых событиях.

person Davorin Ruševljan    schedule 07.12.2012