F# Async.SwitchToContext vs. Dispatcher.Invoke



这两个函数(doSyncpostToUI)是否在(WPF)UI线程上执行相同类型的评估?

还是有细微的区别?

我的问题不是关于编码风格,而是关于幕后实际发生的事情。

open System.Threading
open System.Windows.Threading
let doSync (f:'a -> 'b) x = 
async{  do! Async.SwitchToContext SynchronizationContext.Current
return f x
} |> Async.RunSynchronously

let postToUI : ('a -> 'b) -> 'a -> 'b =
fun f x ->
Dispatcher.CurrentDispatcher.Invoke(new System.Func<_>(fun () -> f x), [||])      
|> unbox

它们可能是相同的,这取决于。

Async.SwitchToContext将使异步延续在SynchronizationContext.Post上运行。它发布的内容完全取决于调用doSync的上下文。

WPF 有一个消息泵系统 - 调度程序,它在主(UI)线程上调度工作单元。

现在,postToUI肯定会在调度程序框架上运行委托。 如果从 WPF 上下文中调用doSync,则SynchronizationContext.CurrentDispatcherSynchronizationContext.在引擎盖下:

public override void Send(SendOrPostCallback d, Object state)
{
_dispatcher.Invoke(DispatcherPriority.Send, d, state);         
}
public override void Post(SendOrPostCallback d, Object state)
{
_dispatcher.BeginInvoke(_priority, d, state);
}

你可以看到DispatcherSynchronizationContext最终打电话给Dispatcher.Invoke

所以,总结一下:

  • 如果你在 WPF 上下文中,doSync将调用Dispatcher.BeginInvoke.
  • 如果不在 WPF 上下文中,请doSync将调用当前Post的任何实现SynchronizationContext.
  • 如果您处于任一上下文中,请postToUI会打电话给Dispatcher.Invoke.

附言

由于Invoke块直到返回,而SwitchToContext实际使用Post,因此doSyncpostToUIpostToUIdoSync

最新更新