【问题标题】:Understanding the Dispatcher Queue了解调度程序队列
【发布时间】:2012-07-10 15:55:13
【问题描述】:

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

当新工作到达时,它会被添加到调度程序队列的开头,而当调度程序想要处理工作项时,它会从开头删除。

更一般地说:如果有工作,它会以先进先出的方式存储在队列中,并在没有工作时进行处理。

MSDN 文档here 指的是loopframe

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

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

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

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

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

我知道,有很多问题:-)

【问题讨论】:

  • 第一个问题:为什么?为什么你想用 Dispatcher 做任何事情?通常,Dispatcher 只是 WPF 进程的“消息泵”。它通过 WPF UI 处理所有消息/事件/命令到应用程序代码(例如鼠标移动、单击等)。当调用应用程序 Run 方法时,它调用 PushFrame 以启动该循环。你不能为同一个线程启动另一个; Dispatcher 用于处理 UI 工作。
  • 你读过threading model吗?
  • 这是生产者-消费者问题的标准解决方案:en.wikipedia.org/wiki/Producer-consumer_problem
  • 当调度程序从头开始添加/删除项目时,称为 LIFO。所以基本上它是一个堆栈。
  • “当新工作到达时,它会被添加到调度程序队列的开头”......那么它不是队列。你确定这不是错字吗?

标签: c# wpf asynchronous dispatcher method-invocation


【解决方案1】:

围绕Dispatcher 的文档很少,因此您必须拆解一下才能了解内部工作原理。

调度程序基本上是围绕应用程序的Message Pump 执行工作的东西。有问题的位于windows message loop 的顶部。

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

获取当前正在执行的线程的 Dispatcher 并创建一个 如果尚未与线程关联,则为新的 Dispatcher。

但是,在这个新的调度程序上调用 Run 将被阻塞。

当您执行Dispatcher.PushFrame 时,它会将内部执行循环推入调度程序——这就是frame 的一般概念。从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之外没有办法知道队列的状态。这是内部细节,不暴露在情理之中。

【讨论】:

  • 非常感谢您的详细回答(抱歉耽搁了)
  • “因此,每个应用程序只能有一个 Dispatcher。”。 “获取当前正在执行的线程,如果尚未与该线程关联,则创建一个新线程。” 您可以将 Dispatcher 想象为 messagepump 的扩展,该扩展允许执行委托,而不仅仅是处理消息代码。
  • "在 TranslateAndDispatchMessage 中评估 Dispatcher 中的优先队列,取出并执行操作。" ——不,显然不是;这就是 GetMessage 所做的。
  • @JeroenvanLangen 已更正。请查看。
  • @JimBalter 谢谢,为了清楚起见,我已经更改了措辞。
猜你喜欢
  • 1970-01-01
  • 2019-01-01
  • 2011-02-11
  • 1970-01-01
  • 2013-10-20
  • 1970-01-01
  • 2011-10-28
  • 2023-03-06
  • 1970-01-01
相关资源
最近更新 更多