【问题标题】:Is checking the Thread is "UI Thread" before Calling Dispatcher.Invoke redundant?在调用 Dispatcher.Invoke 之前检查线程是否为“UI 线程”是多余的?
【发布时间】:2018-01-23 16:34:20
【问题描述】:

关于

Application.Current.Dispatcher.Invoke(action);

我查看了CheckAccess() 以及确定我是否在主 UI 线程上的各种方法。虽然在查看了Dispatcher Source codeInvoke 之后,它似乎调用了CheckAccess() 并执行了其他检查

调用源代码

public void Invoke(Action callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
{
   ...
   ...

   // Fast-Path: if on the same thread, and invoking at Send priority,
   // and the cancellation token is not already canceled, then just
   // call the callback directly.
   if (!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
   {
      SynchronizationContext oldSynchronizationContext = SynchronizationContext.Current;

      try
      {
         DispatcherSynchronizationContext newSynchronizationContext;
         if (BaseCompatibilityPreferences.GetReuseDispatcherSynchronizationContextInstance())
         {
            newSynchronizationContext = _defaultDispatcherSynchronizationContext;
         }
         else
         {
            if (BaseCompatibilityPreferences.GetFlowDispatcherSynchronizationContextPriority())
            {
               newSynchronizationContext = new DispatcherSynchronizationContext(this, priority);
            }
            else
            {
               newSynchronizationContext = new DispatcherSynchronizationContext(this, DispatcherPriority.Normal);
            }
         }
         SynchronizationContext.SetSynchronizationContext(newSynchronizationContext);

         callback();
         ...

所以检查是否需要调用我的对话框最可靠的方法是调用Invoke?当我无法访问Control 时,查看CheckAccessSynchronisationContexts 解决方案似乎是多余的。

是这种情况还是我遗漏了一些边缘情况,或者我看不到隐藏的性能损失?

【问题讨论】:

    标签: wpf dispatcher ui-thread


    【解决方案1】:

    我想这取决于。

    如果您主要追求正确性和/或代码简洁,那么是的,调用是多余的 - 调用

    Dispatcher.Invoke(action);
    

    将在功能上等同于1

    if(Dispatcher.CheckAccess())
        action();
    else
        Dispatcher.Invoke(action);
    

    但是,如果您关心的是性能,那么它就不那么明显了。 CheckAccess 字面意思是

    return Thread == Thread.CurrentThread;
    

    所以即使它被调用了两倍,它也几乎不会被注意到。 Dispatcher.Invoke 但是做了一些额外的工作,比如参数检查,可能还有交换同步上下文,所以我猜它可能比对 CheckAccess() 的冗余调用有更大的开销。但是,与通常的性能优化一样,没有单一的正确答案 - 这取决于您的特定情况(例如,从非 UI 线程调用此代码的可能性)。


    1 显然,在调用 Dispatcher.Invoke 时同步上下文可能会发生其他事情,但除非 action 正在使用它,否则结果是一样的

    【讨论】:

    • 特定的用例是它只是不知道线程是否是 UI,长话短说它基本上是一个全局错误处理程序,用于通过对话框提醒用户的最后努力。不过感谢您的详细回复
    猜你喜欢
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多