Я читал противоречивые мнения относительно того, должен ли каждый BeginInvoke () совпадать с EndInvoke (). Есть ли утечки или другие проблемы, связанные с НЕ вызовом EndInvoke ()?
Является ли EndInvoke () необязательным, отчасти необязательным или определенно необязательным?
Ответы (7)
Delegate.EndInvoke задокументирован как вы должны называть это (т.е. необходимо - иначе произойдут утечки) - из msdn:
Важное примечание
Независимо от того, какой метод вы используете, всегда вызывайте EndInvoke для завершения асинхронного вызова.
Control.EndInvoke можно игнорировать для методов "запустил и забыл" - из msdn а>:
Вы можете вызвать EndInvoke, чтобы получить возвращаемое значение от делегата, если необходимо, но это не обязательно.
Однако - если вы используете Delegate.BeginInvoke
и не хотите результата, подумайте об использовании вместо этого ThreadPool.QueueUserWorkItem
- это значительно упростит жизнь и позволит избежать боли IAsyncResult
и т. Д.
EndInvoke не является обязательным.
Дополнительная информация здесь
И вызов EndInvoke не является необязательным, это часть контракта. Если вы вызываете BeginInvoke, вы должны вызвать EndInvoke.
Классический пример того, зачем это нужно. Вполне возможно, что IAsyncResult, возвращенный из BeginInvoke, выделил прикрепленные к нему ресурсы. Чаще всего это своего рода WaitHandle. Поскольку IAsyncResult не реализует IDisposable, необходимо выбрать другое место для освобождения ресурсов. Единственное место для этого - EndInvoke.
Я кратко расскажу об этой проблеме в следующем сообщении блога.
http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx
EndInvoke не является необязательным, потому что это место, где возникают исключения, если что-то пошло не так в асинхронной обработке.
В любом случае утечки быть не должно, потому что, если IAsyncResult содержит некоторый собственный ресурс, он должен правильно реализовать IDisposable и удалить такие ресурсы, когда GC вызывает свой финализатор.
Это не обязательно, потому что при вызове BeginInvoke используется WaitHandle, который, в свою очередь, использует объект ядра, который поддерживает счетчик количества ссылок на него. Вызов EndInvoke изящно освобождает дескриптор, который уменьшает этот счетчик на объекте ядра, и когда этот счетчик достигает нуля, диспетчер объектов ядра уничтожает его.
Это необязательно только в том случае, если вы не против, чтобы память вашей программы стала очень большой. Проблема в том, что сборщик мусора удерживает все ссылки в вашем потоке, потому что в какой-то момент вы можете захотеть вызвать EndInvoke. Я бы согласился с ответом Марка, пул потоков облегчит вашу жизнь. Однако вам нужно быть осторожным, если вы создаете потоки из своих потоков, так как количество потоков, которые он может развернуть, ограничено.
В каждом ответе на этот пост говорится, что EndInvoke () не является обязательным. Однако я нашел следующий высоко оцененный комментарий, который является принятым ответом на эту тему SO:
«Обратите внимание, что команда Windows Forms гарантирует, что вы можете использовать Control.BeginInvoke в режиме« выстрелил и забыл », то есть никогда не вызывая EndInvoke. Это не относится к асинхронным вызовам в целом: обычно каждый BeginXXX должен иметь соответствующий вызов EndXXX , обычно в обратном вызове ".
В чем разница между Invoke () и BeginInvoke ()
Control.BeginInvoke
и Delegate.BeginInvoke
имеют одно и то же имя, поскольку у них совершенно разная семантика; По правде говоря, мне любопытно, почему типы делегатов определяют, что BeginInvoke
является методом экземпляра, а не Delegate.Bind(params)
возвращает MethodInvoker
[делегат с нулевым аргументом], который будет вызывать делегат с указанными параметрами и который может быть передан, например, ThreadPool.BeginInvoke
метод.
- person supercat; 06.03.2014