了解Dispatcher队列

mar*_*man 17 c# wpf asynchronous dispatcher method-invocation

我想我需要一些帮助来理解Dispatcher Queue.

当新工作到达时,它会在调度程序队列的开头添加,并且当Dispatcher想要处理工作项时,它将从头开始删除.

更一般地说:如果有工作,它将以FIFO方式存储在队列中并且只要没有工作就可以处理.

这里的MSDN文档是指a loop和a frame:

The Dispatcher processes the work item queue in a loop. The loop is referred to as a frame.

但在这种情况下,循环在哪里?对我来说,循环是迭代某些东西的东西,当它到达终点时,它会重新开始.

什么是概念frame?根据MSDN文档,框架是队列中工作项的一击?如果这是真的,应该如何使用静态方法Disptatcher.PushFrame()

最有趣的问题是,是否有任何方法可以获得队列的当前状态,尤其是队列中有多少项.

如果之前调用的方法(以及因此放入Dispatcher队列中)被执行,然后立即将其从队列中删除或者在内部持续另一段时间,它是否成立?

我知道,这么多问题:-)

Ast*_*sti 26

围绕着它的文档非常少Dispatcher,所以你必须对它进行反汇编以了解内部工作原理.

调度程序基本上是围绕应用程序的消息泵执行工作的东西 .有问题的一个位于Windows消息循环的顶部.

因此,只能有一个应用程序Dispatcher - 可访问的全局调度程序对象Application.Current.Dispatcher.其他调度员可以通过访问Dispatcher.CurrentDispatcher,根据文档

获取当前正在执行的线程的Dispatcher,并创建一个新的Dispatcher(如果尚未与该线程关联).

但是,调用Run这个新的调度程序将会阻塞.

当你这样做时Dispatcher.PushFrame,它基本上将一个帧推到当前的调度程序上.任何继承自DispatcherObject此类的东西DispatcherFrame都会将其调度程序设置为当前的调度程序.我们可以通过查看它的构造函数来验证这一点.

private Dispatcher _dispatcher;

protected DispatcherObject()
{
    this._dispatcher = Dispatcher.CurrentDispatcher;
}
Run Code Online (Sandbox Code Playgroud)

当然,拥有一个简单的事件循环是不够的 - 有时您需要破坏当前的事件循环以强制完成其他工作.这就是为什么你有一个DispatcherFrame.这实际上构成了事件循环.当您将帧推入Dispatcher时,会发生以下情况:

while (frame.Continue)
        {
            if (!this.GetMessage(ref msg, IntPtr.Zero, 0, 0))
            {
                break;
            }
            this.TranslateAndDispatchMessage(ref msg);
        }
Run Code Online (Sandbox Code Playgroud)

TranslateAndDispatchMessage取消消息之后,Dispatcher中的优先级队列被评估.

如果一个操作需要很长时间才能在调度程序上运行,它会暂时停止事件循环,并且因为它不响应信号,应用程序似乎停止响应.

这篇文章使用框架强制UI响应,允许事件循环很快运行.

至于访问队列,实际上,无法知道Dispatcher外部队列的状态.这是一个内部细节,它没有暴露是合理的.

  • _"因此,每个应用程序只能有一个Dispatcher."_.<=不是这样,调度程序实例将绑定在线程上.请参阅Dispatcher.CurrentDispatcher的摘要:_"获取当前正在执行的线程,如果尚未与线程关联,则创建一个新的."_您可以将Dispatcher想象为messagepump的扩展,扩展允许执行代表而不是仅处理消息代码. (6认同)