Чтобы дать правильный ответ на этот вопрос, нужно приложить некоторые усилия, потому что короткий ответ («нет») может ввести в заблуждение.
В описании API явно говорится, что вы должны вызывать EndPeek()
для каждого вызова BeginPeek()
? Ни в одной теме, которую я смог найти, и не только в ней, похоже, утверждается обратное здесь :
Чтобы использовать BeginPeek
, создайте обработчик событий, который обрабатывает результаты асинхронной операции, и свяжите его с вашим делегатом события. BeginPeek
инициирует асинхронную операцию просмотра; MessageQueue
уведомляется посредством создания события PeekCompleted
, когда сообщение поступает в очередь. Затем MessageQueue
может получить доступ к сообщению, вызвав EndPeek(IAsyncResult)
или, получив результат с помощью метода PeekCompletedEventArgs
.
(Выделение мое.) Кажется, это говорит о том, что вы можете либо использовать .EndPeek()
, либо просто напрямую получить сообщение из аргументов события без необходимости вызывать .EndPeek()
.
Хорошо, значит, реализация требует, чтобы вы вызывали .EndPeek()
, чтобы все работало правильно? По крайней мере, для реализации System.Messaging
в .NET 4.0 ответ отрицательный. При вызове .BeginPeek()
выделяется асинхронная операция и регистрируется обратный вызов для завершения. Неуправляемые ресурсы, связанные с этой операцией, частично очищаются в этом обратном вызове, и только затем вызывается обработчик события. .EndPeek()
на самом деле не выполняет никакой очистки — он просто ожидает завершения операции, если она еще не завершена, проверяет наличие ошибок и возвращает сообщение. Так что это действительно правда, что вы можете либо вызвать .EndPeek()
, либо просто получить доступ к сообщению из аргументов события, либо вообще ничего не делать - все это будет работать так же плохо.
Плохо, да — заметьте, я сказал «частично очищен». Реализация MessageQueue
имеет проблему в том, что она выделяет ManualResetEvent
для каждой асинхронной операции, но никогда не удаляет ее, оставляя это полностью на усмотрение сборщика мусора — разработчики .NET часто подвергаются резкой критике за то, что они делают, но, конечно, собственные разработчики Microsoft не тоже не идеально. Я не проверял, актуальна ли утечка OverlappedData
, описанная в этом вопросе, и это сразу видно из первоисточника, но меня бы это не удивило.
У API есть и другие предупреждающие признаки того, что его реализация может оставлять желать лучшего, в первую очередь то, что он не следует установленному шаблону .Begin...()
/.End...()
для асинхронных операций, а вводит обработчики событий посередине, создавая странный гибрид, которого я никогда нигде не видел. еще. Затем есть очень сомнительное решение сделать класс Message
наследником Component
, что значительно увеличивает нагрузку на каждый экземпляр и поднимает вопрос о том, когда и как его следует удалять... в общем, не лучшая работа Microsoft.
Значит ли это, что вы не «обязаны» звонить .EndPeek()
? Да, в том смысле, что вызов или не вызов не имеет функционального значения в отношении очистки ресурсов или корректности. Но несмотря на все вышесказанное, я все равно советую назвать его в любом случае. Почему? Потому что любой, кто знаком с тем, как работает шаблон асинхронной операции в других классах .NET, будет ожидать, что вызов будет там, и его отсутствие выглядит как ошибка, которая может привести к утечке ресурсов. Если есть проблема с приложением, такой человек может разумно потратить некоторые бесплодные усилия на поиск «проблемного кода», который не является таковым. Учитывая, что вызов .EndPeek()
имеет незначительные накладные расходы по сравнению с остальным механизмом, я бы сказал, что экономия на программистах больше удивляет, чем компенсирует затраты. Возможная альтернатива состоит в том, чтобы вместо этого вставить комментарий, объясняющий, почему вы не вызываете .EndPeek()
, но, по всей вероятности, для понимания этого потребуется больше программных циклов, чем просто вызов.
Теоретически еще одна причина для его вызова заключается в том, что семантика API может измениться в будущем, чтобы сделать вызов .EndPeek()
необходимым; на практике это очень маловероятно, потому что Microsoft традиционно неохотно вносит подобные критические изменения (код, который ранее и разумно не вызывал .EndPeek()
, перестанет работать), а существующая реализация уже противоречит установившейся практике.
person
Jeroen Mostert
schedule
19.11.2014
.EndPeek()
? Если вам не нужен результат.EndPeek()
, вы можете отказаться от него, но не вызывать его вообще почти наверняка плохая идея — вы, по сути, делаете ставку на то, что.BeginPeek()
не выделяет никаких неуправляемых ресурсов, которые.EndPeek()
должен освободить. Даже если сейчас это так, кто сказал, что следующий релиз не нарушит это предположение? - person Jeroen Mostert   schedule 18.11.2014EndPeek()
, а потомReceive()
для верности... - person pleinolijf   schedule 18.11.2014System.Messaging.dll
, которую вы используете, имеет реализацию.BeginPeek()
, которая распределяет или не выделяет ресурсы, ничего не доказывает, кроме того, что ваш код в настоящее время работает (не) работает. - person Jeroen Mostert   schedule 18.11.2014EndPeek()
, а затемReceive()
. Но это потому, что вы решили позвонитьBeginPeek()
, а неBeginReceive()
. Считаете ли вы логичным, чтобыReceive()
проверял все невыполненныеBeginPeek()
запросы, чтобы очистить их? - person Jeroen Mostert   schedule 18.11.2014BeginPeek()
, чтобы фактическое получение сообщения можно было выполнить в рамках транзакции. Мне не удалось сделать это сBeginReceive()
в такой настройке. Есть ли способ использоватьEndPeek()
, а затем удалить сообщение из очереди (без использованияReceive()
? - person pleinolijf   schedule 18.11.2014BeginReceive()
с транзакциями, а вместо этого должны использоватьBeginPeek()
, так что все в порядке - однако затем не говорится, что вы можете не вызыватьEndPeek()
. Я по-прежнему не вижу проблемы — просто вызовитеEndPeek(asyncResult)
, игнорируя результат, и покончим с этим. Это, скорее всего, даже не повлечет за собой каких-либо (предотвратимых) накладных расходов, поскольку вы все равно уже начали операцию просмотра - не завершение ее не устраняет ее. - person Jeroen Mostert   schedule 18.11.2014