Какой самый эффективный для процессора способ "тратить время" в потоке?
У меня есть несколько потоков (100), которые выполняются в течение нескольких секунд за раз. Когда они выполняются, они проводят значительное количество времени, ожидая ответа от другой системы (последовательное устройство). Я помню, что одновременное выполнение 100 потоков могло быть ресурсом hog, поэтому я фактически ограничиваю количество потоков, которые могут запускаться в любой момент.
Мне кажется, что должны быть хорошие и плохие способы ожидания внешнего события внутри потока. Является ли этот подход интенсивным??:
send command ;
repeat
until response arrived ;
process response ;
и делает ли этот подход более эффективным?:
send command ;
repeat
Sleep (20) ;
until response arrived ;
process response ;
* ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ *
Среда - x86 Windows XP. Код потока представляет собой длинную и вовлеченную последовательность взаимодействий с последовательным устройством, но в целом он состоит из записи символов в COM-порт (с использованием последовательной библиотеки AsyncFree) и ожидание возвращения символов путем размещения в буфере входящих символов и обрабатывая их, когда они прибудут. Я полагаю, что последовательная библиотека делает чтение и запись устройств. Время в потоке может составлять целую минуту или как можно короче, чем через пару секунд, но большая часть времени тратится на то, чтобы символы покинули порт или ожидали ответные символы (скорость в бодах медленная), поэтому мой вопрос о лучшем способе поведения потока во время ожидания. В настоящее время я вызываю Sleep
в цикле, ожидая, когда CharactersInBuffer
станет ненулевым, обработает каждый символ, когда он поступит, и выйдет из потока, когда у меня будет полный ответ. Таким образом, код больше похож (игнорируя обработку тайм-аутов и т.д.):
send command ;
Packet = '' ;
repeat
repeat
Sleep (20) ;
until response character arrived ;
build Packet
until complete packet arrived
process response ;
Ответы
Ответ 1
Если поток действительно ждет с чем-то вроде WaitForSingleObject, который не использует процессорное время, то время от времени, нет причин помещать задержку в потоке со сном.
Ваш пользователь не ждет от потока ответа, он не использует процессорное время, а другие потоки не будут заблокированы, поэтому нет причин помещать поток в режим сна.
Как указал Дэвид Хеффернан в своем комментарии, если теперь он не использует 100% вашего процессора, тогда проблем нет.
Вы можете использовать sleep(), если бы вы были однопоточными, и вам приходилось иногда отвечать на запросы пользователя, ожидая ответа на последовательный порт.
Кроме того, наличие спящего потока не сделает его более эффективным. Это просто приведет процессорные циклы к другим потокам.
Взгляните на sleep(0)
как эффективный способ "потерять время" процессора в потоке.
Ответ 2
Самый эффективный способ предотвратить поток от использования процессорного времени - поставить его в режим ожидания.
Я не использую delphi вообще, но кажется, что основы для этого есть. См. "Глава 11. Синхронизаторы и события" и более конкретно "Моделирование событий с использованием семафоры" .
Если вы хотите подождать без использования CPU, используйте WaitForEvent
:
Проверяется состояние сигнала события. Если это указывает на то, что событие сигнализируется, тогда сигнализируется внутренний семафор, а количество потоков, заблокированных на семафоре, уменьшается. Затем подсчитывается количество заблокированных потоков, и ожидание выполняется на внутреннем семафоре.
Если это связано с I/O, тогда все работает немного иначе. Если это сокет, то он уже может блокировать, если он асинхронный ввод-вывод, то вы можете использовать семафор и WaitForEvent
и т.д.
В .NET есть Monitor.Wait
, Monitor.Signal
, ManualResetEvent
, CountDownLatch
и т.д., но я не знаю, что эквивалентно в delphi.
Ответ 3
Я не могу говорить о возможностях AsyncFree, но в целом программирование COM-портов в Windows поддерживает Overlapped I/O, поэтому вы можете эффективно ждать уведомления, когда данные поступают с помощью функции WaitCommEvent()
с одним из семейства WaitFor...()
функций, таких как WaitForSingleObject()
. Поток может быть помещен в состояние ожидания до тех пор, пока не будет обнаружено сообщение, и в это время он "просыпается", чтобы читать из порта, пока нет ничего более читаемого, после чего он может вернуться в режим сна до следующего уведомления.