Skip to content

Instantly share code, notes, and snippets.

@eulerfx
Last active April 23, 2025 17:36
Show Gist options
  • Save eulerfx/c731c900db3471f493bcce04cf6d9a0f to your computer and use it in GitHub Desktop.
Save eulerfx/c731c900db3471f493bcce04cf6d9a0f to your computer and use it in GitHub Desktop.
F# Async Cache
let cache (a:Async<'a>) : Async<'a> =
let tcs = TaskCompletionSource<'a>()
let state = ref 0
async {
if (Interlocked.CompareExchange(state, 1, 0) = 0) then
Async.StartWithContinuations(
a,
tcs.SetResult,
tcs.SetException,
(fun _ -> tcs.SetCanceled()))
return! tcs.Task |> Async.AwaitTask }
@njlr
Copy link

njlr commented Apr 23, 2025

Passing in the cancellation token:

open System.Threading
open System.Threading.Tasks

let cache (workflow : Async<'a>) : Async<'a> =
  let tcs = TaskCompletionSource<'a>()
  let mutable state = 0

  async {
    if state = 0 && Interlocked.CompareExchange(&state, 1, 0) = 0 then
      let! ct = Async.CancellationToken

      Async.StartWithContinuations(
        workflow,
        tcs.SetResult,
        tcs.SetException,
        (fun _ -> tcs.SetCanceled()),
        ct
      )

    return! Async.AwaitTask tcs.Task
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment