Вопрос по multithreading, delphi, sleep, delphi-2006, thread-sleep – Какой самый эффективный способ «тратить время» в потоке?

11

У меня есть несколько потоков (100), каждый из которых выполняется по несколько секунд за раз. Когда они выполняются, они тратят значительное количество этого времени на ожидание ответа от другой системы (последовательного устройства). Я не забываю, что одновременное выполнение 100 потоков может быть проблемой, поэтому я ограничиваю количество потоков, которые могут запускаться одновременно.

Мне приходит в голову, что должны быть хорошие и плохие способы ожидания внешнего события внутри потока. Является ли этот подход ресурсоемким ?:

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 ;  
Это зависит от того, что делает цикл. Можете ли вы предоставить код? Marcus Adams
@rossmcm: у потока должен быть способ дождаться уведомления от ОС о том, что ответ доступен, а не опрашивать его. afrazier
@rossmcm Если ваши темы уже блокируют, вам, вероятно, нечего делать. David Heffernan
Пожалуйста, опубликуйте свою ОС, это может быть актуально. Chris O
Если вы не видите, что загрузка вашего процессора составляет 100%, значит, у вас нет проблем. Не видя реального кода, сложно сказать больше.until response arrived это ключ. Что это на самом деле делает? Это блокирующий вызов? David Heffernan

Ваш Ответ

3   ответа
2

мени потоком - перевести его в «режим ожидания».

Я вообще не использую Delphi, но кажется, что основы для этого есть. Видеть«Глава 11. Синхронизаторы и события» и, более конкретно«Моделирование событий с использованием семафоров».

Если вы хотите ждать без использования процессора, то используйтеWaitForEvent:

Состояние сигнала события изучается. Если это указывает, что событие сигнализировано, то внутренний семафор сигнализируется, и число потоков, заблокированных на семафоре, уменьшается. Затем количество заблокированных потоков увеличивается, и на внутреннем семафоре выполняется ожидание.

Если это связано с вводом / выводом, то все работает немного иначе. Если это сокет, то он может уже блокироваться, если это асинхронный ввод-вывод, тогда вы можете использовать семафор иWaitForEvent и так далее.

В .NET естьMonitor.Wait, Monitor.Signal, ManualResetEvent, CountDownLatchи т. д., но я не знаю, каковы эквивалентные вещи в Delphi.

7

который не использует процессорное время, то время ожидания истекло, поэтому нет никакой причины помещать задержку в поток со сном.

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

Как отметил в своем комментарии Дэвид Хеффернан, если сейчас он не использует 100% вашего процессора, то проблем нет.

Вы можете использовать sleep (), если вы были однопоточными, и вам приходилось время от времени отвечать пользователю в ожидании ответа от последовательного порта.

Кроме того, нить сна не сделает его более эффективным. Это просто дало бы циклы процессора другим потокам.

Взгляни наsleep(0) как эффективный для процессора способ «тратить время» в потоке.

Хорошо, теперь я понимаю, что Sleep (0) фактически говорит: «Двигайся, тут ничего не поделаешь», поэтому, если я буду придерживаться своей текущей архитектуры, ограничив число потоков, которые могут начинаться до десяти, и заменив свой Sleep (20) Sleep (0), у меня будет ситуация с низкой задержкой и низкой загрузкой процессора? rossmcm
@rossmcmSleep(0) выдаст, только если есть готовый поток, ожидающий. В противном случае это нет. David Heffernan
Also, having a thread sleep would not make it more efficient. It would simply yield processor cycles to other threads. Разве это не главное? Если я переведу свой поток в спящий режим до 20 мс и уступлю обработку другим потокам, разве это не сделает больше ЦП доступным для других потоков / других процессов? Если у меня 10000 потоков и все они только что перешли в состояние ожидания (10000), каково их общее использование ЦП? rossmcm
@rossmcm, с Sleep (0) вместо Sleep (20) вы будете иметь низкую задержку, но вам гарантированно более высокая загрузка ЦП, пока есть работа. Загрузка процессора не плохая. Если никто больше не использует процессор, то почему не вы? Sleep (0) будет держать компьютер реагирующим на другие процессы, что помогает поддерживать отзывчивость пользовательского интерфейса и позволяет пользователю продолжать смотреть свои фильмы или просматривать веб-страницы во время работы вашей программы. Если вы хотите намеренно заставить пользователя ждать дольше с помощью Sleep (20), просто чтобы он не видел скачок процессора, это ваша прерогатива. Я предпочитаю, чтобы они думали, что их компьютер работает медленно, а не моя программа. Marcus Adams
@ crossmom, если я в колонне, остановка грузовика, чтобы пропустить других, не увеличивает эффективность. Тот же объем работы должен быть сделан. Это просто более вежливо. Если я остановлю свой грузовик, когда никого не пропущу, я потрачу время. Если 10000 потоков находятся в спящем режиме, технически они используют 0 ЦП, хотя потоку операционной системы (планировщика) предстоит проделать большую работу, и если у вас закончится ОЗУ, вы наверняка замедлитесь. Использование sleep (0) сделает все как можно быстрее, но в то же время будет вежливым. Sleep (0) более эффективен, чем sleep (200), поскольку время также является ресурсом. Marcus Adams
2

но в целом программирование COM-порта в Windows поддерживает перекрывающийся ввод-вывод, поэтому вы можете эффективно ждать уведомления при поступлении данных, используяWaitCommEvent() функция с одним изWaitFor...() семейство функций, таких какWaitForSingleObject(), Поток может быть переведен в состояние сна до тех пор, пока не возникнет проблема с уведомлением, и в этот момент он «просыпается» для чтения из порта, пока больше нечего читать, затем он может вернуться в спящий режим до следующего уведомления.

Похожие вопросы