Подтвердить что ты не робот

Действительно ли необходим Delegate.EndInvoke()?

Я прочитал пару форумов и даже вопрос или два вопроса о stackoverflow, говорящий, что Delegate.EndInvoke необходим при использовании Delegate.BeginInvoke. Многие из статей, которые я читал, говоря об использовании BeginInvoke, не упоминали об использовании EndInvoke. Также я развернул производственный код, используя только BeginInvoke, и, похоже, проблем с памятью не возникает. Как я использовал BeginInvoke, как правило, с потоками, которые меня не волнуют, когда они заканчивают или как долго они обрабатывают.

4b9b3361

Ответ 1

Из статьи MSDN "Синхронные вызовы асинхронно" :

Независимо от того, какой метод вы используете, всегда вызывайте EndInvoke, чтобы завершить асинхронный вызов.

Теперь есть теория, а затем есть практика. Вы нашли, как и многие другие разработчики, перед вами, что вы часто можете избежать игнорирования этого документированного требования. Возможно, это деталь реализации, действительно ли EndInvoke делает что-то абсолютно необходимое для предотвращения сбоя вашего приложения, утечки памяти и т.д. Но вот что: , если это документированное требование, вы действительно должны это сделать. Речь идет не только о теории; о защите себя в случае изменения.

Задокументировав это требование, разработчики этого механизма асинхронного вызова в принципе предоставили себе свободу изменить способ BeginInvoke и EndInvoke работать по линии, чтобы, если бы была достаточная причина (например, повышение производительности), EndInvoke может внезапно стать намного более необходимым. Предположим, что это внезапно приведет к тупиковой ситуации, если вы ее забудете. Они уже покрывали себя, говоря, что всегда звоните EndInvoke; если ваше приложение перестает работать, потому что вы не следовали этому требованию, бремя на вас.

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

Ответ 2

Это абсолютно необходимо, если вы планируете бросать исключения из своего потока и надеяться поймать их должным образом. Если вы не вызываете EndInvoke, поток, который генерирует исключение, исчезнет, ​​и вы ничего не узнаете об этом.

Чтобы поддерживать EndInvoke, предоставьте AsyncCallback и в этом методе обратного вызова обязательно заверните свой вызов в EndInvoke с помощью блока try/catch.

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

Ответ 3

Я слышал о проблемах с утечкой памяти, которые могут возникнуть.

При поиске по ключевым словам я нашел хорошее обсуждение.

Does not calling EndInvoke *really* cause a memory leak ?

It can but it won't necessarily. Technically there is no such thing as a memory leak in .NET. Eventually the memory will be reclaimed by the GC. The problem is that it might be around a long time. The reason that you should call EndInvoke is because the results of the invocation (even if there is no return value) must be cached by .NET until EndInvoke is called. For example if the invoked code throws an exception then the exception is cached in the invocation data. Until you call EndInvoke it remains in memory. After you call EndInvoke the memory can be released.

Вот ссылка ,

Еще одна ссылка

Ответ 4

MSDN сообщает, что важно вызвать EndInvoke:

Важное примечание Независимо от того, какой метод вы используете, всегда звоните EndInvoke для завершения асинхронный вызов.

Ответ 5

Было зарегистрировано, что EndInvoke не требуется (не назначены не управляемые ресурсы — предполагается, что вы не ждете от IAsyncResult) при использовании BeginInvoke для выполнения действий в потоке графического интерфейса в WinForms приложение.

Однако это конкретное исключение из общего правила: для каждого BeginOperation должно быть сопоставление EndOperation. Как отмечено на другом A здесь: если код доступа GUI может быть брошен, вам понадобится EndInvoke, чтобы получить исключение.

См. здесь официальное подтверждение: http://blogs.msdn.com/b/cbrumme/archive/2003/05/06/51385.aspx#51395 (это комментарий от Chris Brummie 12 May 2003 5:50pm.

Дополнительно: Документация для Control.BeginInvoke включает следующее замечание:

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

Итак, это официально: с помощью WinForm, использующего асинхронный делегат для выполнения действия в потоке GUI, не требуется EndInvoke (если вам не требуется возвращаемое значение или возможное исключение, в любом случае подумайте об использовании Invoke).

Ответ 6

Как я использовал BeginInvoke, как правило, с потоками, которые меня не волнуют, когда они заканчивают или как долго они обрабатывают.

Похоже, вы должны использовать класс Thread вместо асинхронных делегатов.

Если вы заботитесь о результатах или обнаруживаете ошибки (которые оба требуют сортировки результатов/ошибок в исходном потоке), вы можете использовать асинхронные делегаты, и в этом случае вам понадобится EndInvoke. Еще лучше, используйте классы Task или Task<TResult>.

Если вы хотите просто отключить некоторую независимую операцию, используйте класс Thread.

Ответ 7

Из Документация Windows Form по Control.BeginInvoke()

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

Это особый случай асинхронного вызова Windows Form в потоке пользовательского интерфейса, и этот это не относится к общему случаю, но это может помочь тем, кто в этой ситуации.