[英]Raising events asynchronously
I'm looking into options for doing asynchronous event dispatching in a component that has many subscribers to its events.我正在研究在具有许多事件订阅者的组件中进行异步事件分派的选项。 In perusing the options, I ran across this example:
在仔细阅读这些选项时,我遇到了这个例子:
public event ValueChangedEvent ValueChanged;
public void FireEventAsync(EventArgs e)
{
Delegate[] delegates = ValueChanged.GetInvocationList();
foreach (Delegate d in delegates)
{
ValueChangedEvent ev = (ValueChangedEvent)d;
ev.BeginInvoke(e, null, null);
}
}
Beyond the older syntax (the sample was from .NET 1.1), it looks to me like this is a serious resource leak.除了较旧的语法(示例来自 .NET 1.1)之外,在我看来这是一个严重的资源泄漏。 There's no completion method, no polling for completion, or any other way that
EndInvoke
will be called.没有完成方法,没有完成轮询,或任何其他将调用
EndInvoke
的方式。
My understanding is that every BeginInvoke
must have a corresponding EndInvoke
.我的理解是每个
BeginInvoke
都必须有一个对应的EndInvoke
。 Otherwise there are pending AsyncResult
object instances floating around, along with (potentially) exceptions that were raised during the asynchronous events.否则,将有待处理的
AsyncResult
object 实例以及在异步事件期间引发的(可能)异常。
I realize that it's easy enough to change that by supplying a callback and doing an EndInvoke
, but if I don't need to.我意识到通过提供回调和执行
EndInvoke
来改变它很容易,但如果我不需要的话。 . . .
.
Handling the asynchronous exeptions is another matter entirely, and, combined with the need to synchronize with the UI thread (ie InvokeRequired
, etc.) could very well tank the whole idea of doing these asynchronous notifications.处理异步异常完全是另一回事,并且结合与 UI 线程(即
InvokeRequired
等)同步的需要,可以很好地解决执行这些异步通知的整个想法。
So, two questions:所以,两个问题:
BeginInvoke
requires a corresponding EndInvoke
?BeginInvoke
都需要相应的EndInvoke
是否正确?A call to BeginInvoke()
should be paired with a EndInvoke()
but not doing it will not result in a resource leak.对
BeginInvoke()
的调用应与EndInvoke()
配对,但不这样做不会导致资源泄漏。 The IAsyncResult
returned by BeginInvoke()
will be garbage collected. BeginInvoke()
返回的IAsyncResult
将被垃圾收集。
The biggest pitfall in this code is you are highly exposed to exceptions terminating the application.这段代码中最大的缺陷是您很容易受到终止应用程序的异常的影响。 You might want to wrap the delegate invocation in an exception handler and put some thought into how you want to propagate the exceptions that happen (report the first, produce an aggregate exception, etc).
您可能希望将委托调用包装在异常处理程序中,并考虑如何传播发生的异常(报告第一个异常,产生聚合异常等)。
Invoking a deletage using BeginInvoke()
will take a thread off the thread queue to start running the event.使用
BeginInvoke()
调用删除将从线程队列中取出一个线程以开始运行事件。 This means that the event will always fire off the main UI thread.这意味着该事件将始终触发主 UI 线程。 This might make some event handler scenarios harder to handle (eg updating the UI).
这可能会使某些事件处理程序场景更难处理(例如更新 UI)。 Handlers would need to realize they need to call
SynchronizationContext.Send()
or .Post()
to synchronize with the primary UI thread.处理程序需要意识到他们需要调用
SynchronizationContext.Send()
或.Post()
来与主 UI 线程同步。 Of course all other multi-thread programming pitfalls also apply.当然,所有其他多线程编程陷阱也适用。
After thinking about this for a while, I came to the conclusion that it's probably a bad idea to do asynchronous events in Windows Forms controls.考虑了一会儿,我得出的结论是,在 Windows Forms 控件中执行异步事件可能是个坏主意。 Windows Forms events should be raised on the UI thread.
Windows Forms 事件应在 UI 线程上引发。 Doing otherwise presents an undue burden on clients, and possibly makes a mess with
AsyncResult
objects and asynchronous exceptions.否则会给客户端带来过度的负担,并且可能会弄乱
AsyncResult
对象和异步异常。
It's cleaner to let the clients fire off their own asynchronous processing (using BackgroundWorker
or some other technique), or handle the event synchronously.让客户端触发他们自己的异步处理(使用
BackgroundWorker
或其他一些技术)或同步处理事件会更干净。
There are exceptions, of course.当然,也有例外。
System.Timers.Timer
, for example, raises the Elapsed
event on a thread pool thread.例如,
System.Timers.Timer
在线程池线程上引发Elapsed
事件。 But then, the initial notification comes in on a pool thread.但是随后,初始通知来自池线程。 It looks like the general rule is: raise the events on the same thread that got the initial notification.
看起来一般规则是:在获得初始通知的同一线程上引发事件。 At least, that's the rule that works best for me.
至少,这是最适合我的规则。 That way there's no question about leaking objects.
这样就没有关于泄漏对象的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.