вторник, 9 ноября 2010 г.

Опрос засыпанием против опроса ожиданием с таймаутом

Это перевод Polling by sleeping versus polling by waiting with a timeout. Автор: Реймонд Чен.

Комментатор Francois Boucher спросил, в фоновом потоке лучше ли делать опрос со Sleep и флагом или опрос с ожиданием на событии?
// Метод A
while fKeepGoing do
begin
  ... немного работы ...
  Sleep(50);
end;

// Метод B
repeat
  ... немного работы ...
until (WaitForSingleObject(hEvent, 50) <> WAIT_TIMEOUT);
Какой сценарий лучше? Первый использует только один описатель - для потока. Второй использует два. Тратит ли первый пример больше потокового времени? Стоит ли использовать ещё и событие (объект ядра)?"

Yeah, whatever.

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

Единственной вещью, о которой я могу здесь подумать, является то, что, расставив эти паузы, вы добились того, что ваш поток не занимает процессор на 100%, когда работает. Хотя это так, но в этом не очень-то много смысла. "Вау, с этими изменениями, моя проверка синтаксиса не загружает процессор больше, чем на 10%!". Да, но при этом она выполняется в десять раз дольше. Это что, улучшение? Вы заставили вашего клиента ждать окончания проверки на порядок больше. Это в десять раз меньше жизни для батареи вашего ноутбука.

И, вообще говоря, опроса следует избегать, потому что он имеет много отрицательных моментов. Поэтому, исходный вопрос можно перефразировать так: "что лучше, забивать гвозди отвёрткой или клещами?"

Но давайте (интереса ради) представим, что этот цикл опроса является правильным дизайном, и что единственное, что нас интересует, - так это вопрос про то, что "лучше", в терминах критериев, указанных выше (описатели, время потока).

По прежнему без разницы.

Метод A использует на один описатель меньше, но добавляет флаг. Т.е. итоговое количество вещей, за которыми вам приходится следить не изменилось.

"Ох, но я сэкономил на накладных расходах для описателя объекта ядра".

Парень, ты уже создал поток. Описатель события - это пыль по сравнению со стоимостью потока.

"Но я сэкономил на проверке допустимости описателя и работе со скрытым объектом ядра".

Слушай, ты собираешься заснуть аж на 50 миллисекунд. Экономия сотни тиков - это пыль по сравнению с 50 миллисекундами.

У метода с флагом есть несколько других проблем, ни одна из которых не является решающим фактором, но про них лучше бы знать.

Во-первых, этот флаг, который вы проверяете. У вас не стоит никакой синхронизации на эту переменную, так что фоновый поток может работать чуточку дольше, чем необходимо, потому что изменение переменной ещё не дошло до процессора, на котором работает цикл опроса. Аналогично, телу этого цикла требуется больше времени, чтобы заметить, что ему нужно остановиться: если флаг fKeepGoing сбрасывается в False во время работы Sleep, то поток всё равно продолжит спать до конца интервала, прежде чем обнаружить это изменение.

В общей схеме, эти дополнительные 50 или сотня миллисекунд, однако, не имеют большого значения. Фоновый поток просто чуть дольше будет останавливаться - вот и всё. Пользователь, вероятно, никогда в жизни не заметит, что загрузка процессора была больше обычного на десятую долю секунды. В конце концов, типичное время реакции пользователя - это 100 миллисекунд и выше.

Я предполагаю, что код, который даёт отмашку фоновому потоку, не ждёт его завершения. Если это не так, что эти 100 миллисекунд могут комбинироваться с другими задержками в работе, давая в итоге заметный результат. Десятая часть секунды здесь, десятая часть там - а в итоге у вас набежит полсекунды. А это задержка, которую мозг человека успеет почувствовать.

2 комментария:

  1. Так я не понял - получается что одно, что другое - разницы нет что ли???
    Мы выяснили - разницы нет?

    ОтветитьУдалить
  2. >>> По прежнему без разницы.

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

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

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

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

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

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