Interop with .NET TPL

TPL : Task Parallel Library

Interaction with .NET libraries

Asynchronous libraries in .NET and the async/await Cβ™― pattern: β†’ Based on TPL and the Task type

Gateways with asynchronous workflow Fβ™― :

  • Async.AwaitTask and Async.StartAsTask functions

  • task {} block

Gateway functions

Async.AwaitTask: Task<'T> -> Async<'T> β†’ Consume an asynchronous .NET library in async block

Async.StartAsTask: Async<'T> -> Task<'T> β†’ Launch an async calculation as a Task

let getValueFromLibrary param = async {
    let! value = DotNetLibrary.GetValueAsync param |> Async.AwaitTask
    return value
}

let computationForCaller param =
    async {
        let! result = getAsyncResult param
        return result
    }
    |> Async.StartAsTask

task {} block

Allows consuming an asynchronous .NET library directly, using a single Async.AwaitTask rather than one for each async method called.

πŸ’‘ Available since Fβ™― 6 (before, we needed the Ply NuGet package)

Async vs Task

1. Calculation start mode

Task = hot tasks β†’ calculations started immediately❗

Async = task generators = calculation specification, independent of startup β†’ Functional approach: no side-effects or mutations, composability β†’ Control of startup mode: when and how πŸ‘

2. Cancellation support

Task: by adding a CancellationToken parameter to async methods β†’ Forces manual testing if token is canceled = tedious + error-prone❗

Async: automatic support in calculations - token to be provided at startup πŸ‘

Recommendation for async functions in Fβ™―

Cβ™― async applied at a method level β‰  Fβ™― async defines an async block, not an async function

☝ Recommendation: » Put the entire body of the async function in an async block.

Pitfalls of the async/await Cβ™― pattern

Pitfall 1 - Really asynchronous?

In Cβ™―: method async remains on the calling thread until the first await β†’ Misleading feeling of being asynchronous throughout the method

Pitfall 2 - Omit the await

Compiles but returns unexpected result: After before Before❗

This pitfall is also present in Fβ™―:

Compiles but returns another unexpected result: no Before at all ⁉️

Compilation warnings

The previous examples compile but with big warnings!

Cβ™― warning CS4014 message:

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the await operator...

Fβ™― warning FS0020 message:

The result of this expression has type Async<unit> and is implicitly ignored. Consider using ignore to discard this value explicitly...

☝ Recommendation: be sure to always handle this type of warnings! This is even more crucial in Fβ™― where compilation can be tricky.

Async.Parallel

Thread-safety

Impure functions can be not thread-safe, for instance if they mutate a shared object like the Console.

It's possible to make them thread-safe using the lock function:

Results in the console (example):

πŸ”— Lock function documentation

Last updated

Was this helpful?