在调用 Dispatcher.Invoke 之前检查线程是否 "UI Thread" 是多余的吗?
Is checking the Thread is "UI Thread" before Calling Dispatcher.Invoke redundant?
关于
Application.Current.Dispatcher.Invoke(action);
我查看了 CheckAccess()
以及确定我是否在主线程 UI 上的各种方法。尽管在查看 Invoke
的 Dispatcher Source code 之后,它似乎调用了 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
时查看 CheckAccess
和 SynchronisationContexts
解决方案似乎是多余的。
是这种情况还是我遗漏了一些边缘情况,或者我看不到隐藏的性能影响?
我想这取决于。
如果您主要追求正确性 and/or 代码简洁,那么是的,调用是多余的 - 调用
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
正在利用它,结果是一样的
关于
Application.Current.Dispatcher.Invoke(action);
我查看了 CheckAccess()
以及确定我是否在主线程 UI 上的各种方法。尽管在查看 Invoke
的 Dispatcher Source code 之后,它似乎调用了 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
时查看 CheckAccess
和 SynchronisationContexts
解决方案似乎是多余的。
是这种情况还是我遗漏了一些边缘情况,或者我看不到隐藏的性能影响?
我想这取决于。
如果您主要追求正确性 and/or 代码简洁,那么是的,调用是多余的 - 调用
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
正在利用它,结果是一样的