Snippets

Tuomas Hietanen Concurrent Memoization

Created by Tuomas Hietanen
module Memoize

//More generic variant of http://www.fssnip.net/c4  
let memoize (f: 'a -> 'b) =
    let cache = System.Collections.Concurrent.ConcurrentDictionary<'a, 'b>()
    fun x -> cache.GetOrAdd(x, f)

// and this works also with F# async functions.
let memoizeAsync f =
    let cache = System.Collections.Concurrent.ConcurrentDictionary<'a, System.Threading.Tasks.Task<'b>>()
    fun x -> // task.Result serialization to sync after done.
        cache.GetOrAdd(x, fun x -> f(x) |> Async.StartAsTask) |> Async.AwaitTask

(*
[<Test>]
let ``async cache should work``() =
    let mutable x = 0
    let someSlowFunc mykey = async { 
        Console.WriteLine "Simulated downloading..."
        do! Async.Sleep 400
        Console.WriteLine "Simulated downloading Done."
        x <- x + 1 // Side effect!
        return "" }
    let memFunc = memoizeAsync <| someSlowFunc
    async {
        do! memFunc "a" |> Async.Ignore
        do! memFunc "a" |> Async.Ignore
        do! memFunc "a" |> Async.Ignore
        do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a")) 
            |> Async.Parallel |> Async.Ignore
        for i = 1 to 30 do
            Async.Start( memFunc "a" |> Async.Ignore )
            Async.Start( memFunc "a" |> Async.Ignore )
        do! Async.Sleep 500
        do! memFunc "a" |> Async.Ignore
        do! memFunc "a" |> Async.Ignore
        for i = 1 to 30 do
            Async.Start( memFunc "a" |> Async.Ignore )
        do! [|1 .. 30|] |> Seq.map(fun _ -> (memFunc "a")) 
            |> Async.Parallel |> Async.Ignore
    } |> Async.RunSynchronously
    x |> shouldEqual 1
*)

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.