Является ли EndInvoke () необязательным, отчасти необязательным или определенно необязательным?

Я читал противоречивые мнения относительно того, должен ли каждый BeginInvoke () совпадать с EndInvoke (). Есть ли утечки или другие проблемы, связанные с НЕ вызовом EndInvoke ()?


person endian    schedule 10.02.2009    source источник
comment
Возможно, вы также захотите увидеть: marcgravell.blogspot.com/2009/02 /async-without-pain.html   -  person Marc Gravell    schedule 11.02.2009


Ответы (7)


Delegate.EndInvoke задокументирован как вы должны называть это (т.е. необходимо - иначе произойдут утечки) - из msdn:

Важное примечание

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

Control.EndInvoke можно игнорировать для методов "запустил и забыл" - из msdn :

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

Однако - если вы используете Delegate.BeginInvoke и не хотите результата, подумайте об использовании вместо этого ThreadPool.QueueUserWorkItem - это значительно упростит жизнь и позволит избежать боли IAsyncResult и т. Д.

person Marc Gravell    schedule 10.02.2009
comment
Спасибо, Марк, вот что послужило поводом для вопроса - я просматривал Рихтера и заметил QueueUserWorkItem, и подумал, подождите, почему я использую BeginInvoke / EndInvoke где-то еще. - person endian; 10.02.2009
comment
@endian - действительно: большую часть использования BeginInvoke можно упростить с помощью ThreadPool; BeginInvoke, возможно, полезен для выполнения некоторых вещей и их последующего сбора обратно ... - person Marc Gravell; 10.02.2009

EndInvoke не является обязательным.

Дополнительная информация здесь

person Luca Martinetti    schedule 10.02.2009
comment
... для делегатов, по крайней мере ;-p - person Marc Gravell; 10.02.2009
comment
из вашей ссылки: единственное задокументированное исключение из правила, о котором я знаю, - это Windows Forms, где вам официально разрешено вызывать Control.BeginInvoke, не беспокоясь о вызове Control.EndInvoke. - person Avram; 10.02.2009

И вызов EndInvoke не является необязательным, это часть контракта. Если вы вызываете BeginInvoke, вы должны вызвать EndInvoke.

Классический пример того, зачем это нужно. Вполне возможно, что IAsyncResult, возвращенный из BeginInvoke, выделил прикрепленные к нему ресурсы. Чаще всего это своего рода WaitHandle. Поскольку IAsyncResult не реализует IDisposable, необходимо выбрать другое место для освобождения ресурсов. Единственное место для этого - EndInvoke.

Я кратко расскажу об этой проблеме в следующем сообщении блога.

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

person JaredPar    schedule 10.02.2009
comment
Спасибо, Джаред, очень признателен. - person endian; 10.02.2009

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

В любом случае утечки быть не должно, потому что, если IAsyncResult содержит некоторый собственный ресурс, он должен правильно реализовать IDisposable и удалить такие ресурсы, когда GC вызывает свой финализатор.

person Maghis    schedule 10.02.2009

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

person James Alexander    schedule 10.02.2009

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

person Steve    schedule 10.02.2009

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

«Обратите внимание, что команда Windows Forms гарантирует, что вы можете использовать Control.BeginInvoke в режиме« выстрелил и забыл », то есть никогда не вызывая EndInvoke. Это не относится к асинхронным вызовам в целом: обычно каждый BeginXXX должен иметь соответствующий вызов EndXXX , обычно в обратном вызове ".

В чем разница между Invoke () и BeginInvoke ()

person Robert Oschler    schedule 18.12.2012
comment
ИМХО, очень жаль, что Control.BeginInvoke и Delegate.BeginInvoke имеют одно и то же имя, поскольку у них совершенно разная семантика; По правде говоря, мне любопытно, почему типы делегатов определяют, что BeginInvoke является методом экземпляра, а не Delegate.Bind(params) возвращает MethodInvoker [делегат с нулевым аргументом], который будет вызывать делегат с указанными параметрами и который может быть передан, например, ThreadPool.BeginInvoke метод. - person supercat; 06.03.2014
comment
+1 за это важное различие. Всезнающий комментарий Скита (цитируемый выше) очень актуален для тех, кто рассматривает ситуации Control.InvokeRequired. - person Special Sauce; 14.03.2017