Какой самый эффективный для процессора способ "тратить время" в потоке?

У меня есть несколько потоков (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(). Поток может быть помещен в состояние ожидания до тех пор, пока не будет обнаружено сообщение, и в это время он "просыпается", чтобы читать из порта, пока нет ничего более читаемого, после чего он может вернуться в режим сна до следующего уведомления.