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)
HTTPSSSH
You can clone a snippet to your computer for local editing.
Learn more.