воскресенье, 9 мая 2010 г.

Стоимость чтения ключа реестра

Это перевод The performance cost of reading a registry key. Автор: Реймонд Чен.

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

Но это не значит, что операции с реестром даются вам за бесплатно.

Стоимость открытия ключа реестра, чтения значения и закрытия составляет от 60'000 до 100'000 циклов процессора (так мне сказали). И это в предположении, что ваш ключ уже находится в кэше. Если вы открываете ключ и держите его открытым, то чтение значения будет стоить вам от 15'000 до 20'000 циклов (эти числа взяты для Windows XP; ваши реальные оценки могут быть другими).

Соответственно, вам не следует делать вещей вроде чтения ключа реестра на каждой итерации цикла. Это не только будет стоить вам времени процессора, но также означает, что данные и структуры реестра для вашего ключа будут вынуждены находиться в кэше и памяти всё это время. Лучше прочитайте его один раз и сохраните в переменную. Не читайте реестр на каждое движение мыши; лучше прочитайте значение и закэшируйте результат. Если вы волнуетесь, что кто-то изменит ваше значение в реестре, пока вы используете значение из кэша, то вы можете предусмотреть протокол, которым другие люди могут уведомлять вас об изменениях. Windows, к примеру, использует функции вроде SystemParametersInfo для изменения настроек, которые обычно хранятся в кэше, а не читаются из реестра каждый раз, когда их кто-то спрашивает. Вызов функции обновления обновляет значение в кэше и в реестре. Если вы не можете или не хотите создавать такой механизм, то вы можете подписаться на уведомления об изменениях через функцию RegNotifyChangeKeyValue, так что вы будете оповещены, когда ваши значения меняют.

Когда только это возможно, оптимизируйте самый частый случай, а не исключения. Типичный случай - это когда значения реестра не меняются. Используя механизм уведомлений, вы перемещаете стоимость "но что если значение поменялось?" из своего цикла в код, который не выполняется в большинстве случаев (запомните: быстрейший код - это код, который не выполняется).

Конечно же, вы не хотите запускать поток только для того, чтобы ждать уведомления. Лично я использую для этого пул потоков (thread pool). Функция RegisterWaitForSingleObject позволяет сказать пулу потоков: "эй, ты не мог бы вызвать меня, когда этот объект просигналит? Ага, спасибо". Пул потоков выполнит работу по комбинированию этого описателя с другими аналогичными описателями и будет ждать любого из них в одном большом вызове WaitForMultipleObjects. Таким образом, один поток может ожидать сразу кучи уведомлений.

Тут, правда, есть подводный камень: функция RegNotifyChangeKeyValue имеет привязку к потоку! Иными словами, если поток, который вызывает функцию RegNotifyChangeKeyValue завершается, то возбуждается уведомление. Это означает, что вам не следует вызывать функцию из потока пула потоков, потому что система удалит потоки в пуле, если работа пула потоков будет завершена и ему нечего будет делать. Если вы напутаете и вызовите её из потока пула потоков, то вы обнаружите, что событие продолжает возбуждаться, когда запускается код очистки пула потоков, что делает наше решение ещё хуже исходной проблемы! Вместо этого вам следует вызвать RegNotifyChangeKeyValue в постоянном потоке (скажем, в том потоке, которому важно наше значение) и зарегистрировать событие в пуле потоков. Когда сработает событие в пуле потоков, обработать изменение, а затем попросить ваш постоянный поток перезапустить RegNotifyChangeKeyValue. Таким способом ваше событие всегда будет ассоциировано с вашим постоянным потоком, вместо временных рабочих потоков пула потоков.

1 комментарий:

  1. Где-то здесь был перевод поста, что реестр рулит, а ini-файлы отстой. Сколько же тогда циклов процессора нужно для получения параметра из файла?

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.