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

Tea*_*Dev 5 f# asynchronous

为了在后台线程上执行操作并避免阻塞 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
}
Run Code Online (Sandbox Code Playgroud)
  1. 我这样做完全正确吗?这是惯用语吗?应该采取不同的做法吗?
  2. 如果这是正确的,我当然不想一直这样做——是否有一种内置的更短的方法来实现同样的事情?现有的Async函数似乎都没有做类似的事情。
  3. 如果没有,将上面的代码变成一个函数有意义吗?

    let onThreadPool operation =
        async {
            let context = SynchronizationContext.Current
            do! Async.SwitchToThreadPool()
    
            let! result = operation
    
            do! Async.SwitchToContext context
    
            return result
        }
    
    Run Code Online (Sandbox Code Playgroud)

这增加了另一个层次的async { }嵌套——这会在“某个”点引起问题吗?

Tom*_*cek 3

你在这里所做的事情绝对是有意义的。这里一个有用的操作是Async.StartImmediate,它在当前线程上启动异步工作流程。如果您从 UI 线程调用此函数,这将保证工作流也将在 UI 线程上启动,因此您可以捕获工作流内的同步上下文。

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

但对于其他异步操作(以及您想要在后台运行的非异步操作),您的onThreadPool函数看起来是执行此操作的好方法。