Объяснение текста о потоковой обработке в “C # 3.0 в двух словах”
-
22-09-2019 - |
Вопрос
Во время чтения C # 3.0 в двух словах Автор: Джозеф и Бен Альбахари, я наткнулся на следующий абзац (страница 673, первый абзац в разделе под названием "Сигнализация с помощью ожидания и импульса")
"Тот самый Монитор класс предоставляет другую конструкцию сигнализации с помощью двух статических методов, Подожди и Пульс.Принцип заключается в том, что вы сами пишете логику сигнализации, используя пользовательские флаги и поля (заключенные в замок заявления), а затем ввести Подожди и Пульс команды для уменьшения вращения процессора.Преимущество этого низкоуровневого подхода заключается в том, что с помощью всего лишь Подожди, Пульс, и тот замок таким образом, вы можете добиться функциональности Автоустановленное событие, ManualResetEvent вручную установить событие, и Семафор, а также Ручка ожиданиястатические методы Подождите все и Подождите , пока.Более того, Подожди и Пульс может быть приемлемым в ситуациях, когда все дескрипторы ожидания требуют скупости. "
Мой вопрос в том, какова правильная интерпретация Последние приговор?
- Ситуация с приличным / большим количеством дескрипторов ожидания, когда WaitOne() вызывается лишь изредка для какого-либо конкретного дескриптора ожидания.
- Ситуация с приличным / большим количеством дескрипторов ожидания, когда редко более одного потока имеют тенденцию блокироваться для какого-либо конкретного дескриптора ожидания.
- Какая-то другая интерпретация.
Также был бы признателен за разъяснение примеров таких ситуаций и, возможно, за то, как и / или почему они более эффективно обрабатываются с помощью Wait и Pulse, а не другими методами.
Спасибо!
Редактировать:Я нашел этот текст в Интернете здесь
Решение
Это говорит о том, что есть некоторые ситуации, когда Wait и Pulse обеспечивают более простое решение, чем дескрипторы wait.В общем, это происходит там, где:
- Официант, а не уведомитель, решает, когда разблокировать
- Условие блокировки включает в себя нечто большее, чем простой флаг (возможно, несколько переменных).
Вы все еще можете использовать дескрипторы ожидания в этих ситуациях, но ожидание / Импульс, как правило, проще.Самое замечательное в Wait / Pulse заключается в том, что Wait снимает базовую блокировку во время ожидания.Например, в следующем примере мы считываем _x и _y в пределах безопасности блокировки - и все же эта блокировка снимается во время ожидания, чтобы другой поток мог обновить эти переменные:
lock (_locker)
{
while (_x < 10 && _y < 20) Monitor.Wait (_locker);
}
Затем другой поток может обновить _x и _y атомарно (в силу блокировки), а затем импульсно подать сигнал официанту:
lock (_locker)
{
_x = 20;
_y = 30;
Monitor.Pulse (_locker);
}
Недостатком Wait / Pulse является то, что легче ошибиться и совершить ошибку (например, обновив переменную и забыв выполнить Pulse).В ситуациях, когда программа с дескрипторами ожидания одинаково проста для программы с Wait / Pulse, я бы рекомендовал использовать дескрипторы ожидания по этой причине.
С точки зрения эффективности / потребления ресурсов (на что, я думаю, вы намекали), Wait / Pulse обычно быстрее и легче (поскольку имеет управляемую реализацию).Однако на практике это редко имеет большое значение.И на этом этапе Framework 4.0 включает управляемые версии ManualResetEvent и Semaphore с низкими накладными расходами (ManualResetEventSlim и SemaphoreSlim).
Framework 4.0 также предоставляет множество дополнительных опций синхронизации, которые уменьшают потребность в ожидании / импульсе:
- Обратный отсчет
- Барьер
- PLINQ / Параллелизм данных (параллельный.Вызывать параллельно.For, Parallel.ForEach)
- Задачи и продолжения
Все они намного более высокого уровня, чем Wait / Pulse, и IMO предпочтительнее для написания надежного и поддерживаемого кода (при условии, что они решат поставленную задачу).