我认为我需要一些帮助来理解 Dispatcher Queue 。
当新工作到达时,它会在调度程序队列的开头添加,并且当Dispatcher想要处理工作项时,它会从头开始删除。
更一般地说:如果有工作,它会以FIFO方式存储在队列中,并且只要没有工作就可以处理。
MSDN文档here指的是loop
和frame
:
The Dispatcher processes the work item queue in a loop. The loop is referred to as a frame.
但在这种情况下,循环在哪里?对我来说,循环是迭代某些东西的东西,当它到达终点时,它会重新开始。
frame
的概念是什么?根据MSDN文档,框架是队列中工作项的一击?如果这是真的,应该如何使用静态方法Disptatcher.PushFrame()
?
最有趣的问题是,是否有任何方法可以获取队列的当前状态,尤其是队列中有多少项。
如果之前调用的方法(以及因此放入Dispatcher队列中)被执行,然后立即从队列中删除,或者在内部持续一段时间,它是否成立?
我知道,这么多问题: - )
答案 0 :(得分:25)
围绕Dispatcher
的文档非常少,因此您需要对其进行反汇编以了解内部工作原理。
调度程序基本上是围绕应用程序Message Pump执行工作的东西。有问题的一个位于windows message loop。
之上因此,只能有一个应用程序Dispatcher - Application.Current.Dispatcher
可访问的全局调度程序对象。其他调度员可以通过访问Dispatcher.CurrentDispatcher
来实现,根据文档
获取当前正在执行的线程的Dispatcher并创建一个 new Dispatcher如果尚未与该线程关联。
但是,在此新调度程序上调用Run
将会阻止。
执行Dispatcher.PushFrame
时,它基本上将帧推送到当前的调度程序。从DispatcherObject
继承的任何内容(例如DispatcherFrame
)都会将其调度程序设置为当前的调度程序。我们可以通过查看它的构造函数来验证这一点。
private Dispatcher _dispatcher;
protected DispatcherObject()
{
this._dispatcher = Dispatcher.CurrentDispatcher;
}
当然,拥有一个简单的事件循环是不够的 - 有时您需要破坏当前的事件循环以强制完成其他工作。这就是你有DispatcherFrame
的原因。这实际上构成了事件循环。当您将帧推入Dispatcher时,会发生以下情况:
while (frame.Continue)
{
if (!this.GetMessage(ref msg, IntPtr.Zero, 0, 0))
{
break;
}
this.TranslateAndDispatchMessage(ref msg);
}
在TranslateAndDispatchMessage
中,在取消消息后,Dispatcher中的优先级队列被评估。
如果一个操作需要很长时间才能在调度程序上运行,它会暂时停止事件循环,并且因为它不响应信号,应用程序似乎停止响应。
Here's an article使用框架强制UI响应,允许事件循环很快运行。
对于访问队列,实际上,无法知道Dispatcher外部队列的状态。这是一个内部细节,它没有暴露是合理的。