使用异步工作流的WPF后台操作

时间:2015-08-28 01:09:04

标签: asynchronous f#

要在后台线程上执行操作并避免阻止WPF应用程序中的UI,我经常会发现自己编写这种模式:

async {
    // some code on the UI thread

    let uiThread = SynchronizationContext.Current
    do! Async.SwitchToThreadPool()

    let! result = // some Async<'t>

    do! Async.SwitchToContext uiThread

    // do things with the result if it wasn't () all along
}
  1. 我这样做了吗?这是惯用的吗?应该采用不同的方式吗?
  2. 如果这是正确的,当然我宁愿不必一直这样做 - 是否有一种内置的更短的方式来实现同样的事情?现有的Async函数似乎都没有这样做。
  3. 如果没有,将上述代码转换为函数是否有意义?

    let onThreadPool operation =
        async {
            let context = SynchronizationContext.Current
            do! Async.SwitchToThreadPool()
    
            let! result = operation
    
            do! Async.SwitchToContext context
    
            return result
        }
    
  4. 这增加了async { }嵌套的另一个级别 - 这会导致“某些”问题吗?

1 个答案:

答案 0 :(得分:3)

你在这里所做的一切都是有道理的。这里有一个有用的操作是Async.StartImmediate,它在当前线程上启动异步工作流。如果从UI线程调用此方法,则可以保证工作流也将在UI线程上启动,因此您可以捕获工作流内的同步上下文。

另一个技巧是许多内置异步F#操作会自动跳回到原始同步上下文(使用Async.FromContinuations创建的那些上下文,包括例如AsyncDownloadString),所以当你打电话时其中之一,您甚至不需要显式跳回原始同步上下文。

但对于其他异步操作(以及您希望在后台运行的非异步操作),您的onThreadPool函数看起来是一种很好的方法。