Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF background operations using Asynchronous Workflows

To execute operations on a background thread and avoid blocking the UI in a WPF application, I often find myself writing this pattern:

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. Am I doing this right at all? Is this idiomatic? Should it be done differently?
  2. If this is correct, of course I would prefer not to have to do it like that all the time - is there a built-in shorter way to achieve the same thing? None of the existing Async functions appears to do something like that.
  3. If not, does it make sense to just turn the above code into a function?

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

That adds another level of async { } nesting - can this cause issues at "some" point?

like image 845
TeaDrivenDev Avatar asked Oct 20 '22 03:10

TeaDrivenDev


1 Answers

What you're doing here definitely makes sense. One useful operation here is Async.StartImmediate, which starts the async workflow on the current thread. If you call this from the UI thread, this guarantees that the workflow will also start on the UI thread and so you can capture the synchronization context inside the workflow.

The other trick is that many built-in asynchronous F# operations automatically jump back to the original synchronization context (those that are created using Async.FromContinuations, including e.g. AsyncDownloadString), so when you're calling one of those, you do not even need to explicitly jump back to the original synchronization context.

But for other asynchronous operations (and for non-async operations that you want to run in the background), your onThreadPool function looks like a great way of doing this.

like image 64
Tomas Petricek Avatar answered Oct 21 '22 22:10

Tomas Petricek