Вопрос

Я видел вопрос о том, почему "опрос - это плохо".С точки зрения минимизации количества процессорного времени, используемого одним потоком, было бы лучше выполнить ожидание вращения (т.е.запрашивать требуемое изменение в цикле while) или ожидать объект ядра (напримеробъект события ядра в Windows)?

Для контекста предположим, что код потребуется для запуска на любом типе процессора: одноядерном, гиперпоточном, многоядерном и т.д.Также предположим, что поток, который будет опрашивать или ждать, не сможет продолжаться до тех пор, пока результат опроса не будет удовлетворительным, если он опрашивал, а не ждал.Наконец, время между началом ожидания потока (или опроса) и выполнением условия потенциально может варьироваться от очень короткого времени до длительного.

Поскольку ОС, вероятно, будет более эффективно "опрашивать" в случае "ожидания", я не хочу видеть аргумент "ожидание просто означает, что кто-то другой выполняет опрос", это старые новости, и они не обязательно точны на 100%.

Это было полезно?

Решение

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

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

Вы специально спрашивали о минимизации процессорного времени для потока:в этом примере блокировка потока для объекта ядра использовала бы НУЛЕВОЕ время;поток опроса будет использовать все виды времени.

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

Другие советы

Ожидание - это "более приятный" способ вести себя.Когда вы ожидаете объект ядра, вашему потоку не будет предоставлено никакого процессорного времени, поскольку планировщику известно, что готовая работа отсутствует.Вашему потоку будет предоставлено процессорное время только тогда, когда будет выполнено условие ожидания.Это означает, что вы не будете без необходимости расходовать ресурсы процессора.

Я думаю, что вопрос, который еще не поднимался, заключается в том, что если вашей операционной системе предстоит много работы, блокировка перенаправляет ваш поток на другой процесс.Если все процессы используют блокирующие примитивы там, где они должны (например, ожидания ядра, файловый / сетевой ввод-вывод и т.д.), Вы предоставляете ядру дополнительную информацию для выбора того, какие потоки следует запускать.Таким образом, он выполнит больше работы за тот же промежуток времени.Если ваше приложение может делать что-то полезное в ожидании открытия этого файла или прибытия пакета, то yeilding поможет даже вашему собственному приложению.

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

Я полагаю, что сделать это в два этапа было бы очень сложно и потребовало бы большого количества тестов и исследований.Поэтому, если у вас нет времени и ресурсов, придерживайтесь примитивов Windows...они уже провели исследование за вас.

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

Я согласен с Darksquid, если в вашей операционной системе есть приличные примитивы параллелизма, то вам не нужно проводить опрос.опрос обычно выполняется самостоятельно в системах реального времени или на оборудовании с ограниченным доступом, у которого нет ОС, тогда вам нужно выполнить опрос, потому что у вас может не быть возможности wait (), но также потому, что это дает вам точный контроль над тем, как долго вы хотите ждать в определенном состоянии, в отличие от того, чтобы зависеть от планировщика.

Ожидание (блокировка) почти всегда является лучшим выбором ("наилучшим" в смысле эффективного использования ресурсов обработки и минимизации воздействия на другой код, выполняемый в той же системе).Основными исключениями являются:

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

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

Можно было бы использовать четыре основных подхода:

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

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

Подход №3 довольно грубый, но во многих случаях может оказаться хорошим.Это часто будет отнимать больше процессорного времени и ресурсов, чем подход № 1, но во многих случаях это будет проще реализовать, и потери ресурсов во многих случаях будут достаточно малы, чтобы не иметь значения.

Подход № 2 часто сложнее, чем № 3, но имеет преимущество в возможности обрабатывать множество ресурсов с помощью одного таймера и без выделенного потока.

Подход № 4 иногда необходим во встроенных системах, но, как правило, очень плох, если только не опрашивать аппаратное обеспечение напрямую и не делать ничего полезного до тех пор, пока не произойдет рассматриваемое событие.Во многих случаях выполнение ожидаемого условия будет невозможно до тех пор, пока ожидающий его поток не передаст данные центральному процессору.Загрузка процессора, как в подходе № 3, фактически позволит ожидающему потоку увидеть событие раньше, чем это привело бы к его блокировке.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top