gpt4 book ai didi

f# - 是时候在 F# 中实现记忆化了

转载 作者:行者123 更新时间:2023-12-02 20:47:31 25 4
gpt4 key购买 nike

不确定我是否做对了,或者是否有更好的方法或现有的库已经解决了这个问题。

特别是,我不确定 CAS 是否需要内存栅栏……我认为不需要,但最好问一下。

我还尝试过使用代理和可变字典,但我的直觉是它会更慢,这一点得到了证实,而且实现也更加复杂。

module CAS =
open System.Threading

let create (value: 'T) =
let cell = ref value

let get () = !cell

let rec swap f =
let before = get()
let newValue = f before
match Interlocked.CompareExchange<'T>(cell, newValue, before) with
| result when obj.ReferenceEquals(before, result) ->
newValue
| _ ->
swap f

get, swap

module Memoization =
let timeToLive milis f =
let get, swap = CAS.create Map.empty

let evict key =
async {
do! Async.Sleep milis
swap (Map.remove key) |> ignore
} |> Async.Start

fun key ->
let data = get()
match data.TryFind key with
| Some v -> v
| None ->
let v = f key
swap (Map.add key v) |> ignore
evict key
v

最佳答案

如果您愿意将要内存的内容限制为接受字符串输入的函数,则可以重用 System.Runtime.Caching 中的功能。

作为核心库的一部分,这应该相当强大(您希望...),但是字符串限制非常严重,如果您想进行比较,则必须针对当前的实现进行基准测试性能。

open System
open System.Runtime.Caching

type Cached<'a>(func : string -> 'a, cache : IDisposable) =
member x.Func : string -> 'a = func

interface IDisposable with
member x.Dispose () =
cache.Dispose ()

let cache timespan (func : string -> 'a) =
let cache = new MemoryCache(typeof<'a>.FullName)
let newFunc parameter =
match cache.Get(parameter) with
| null ->
let result = func parameter
let ci = CacheItem(parameter, result :> obj)
let cip = CacheItemPolicy()
cip.AbsoluteExpiration <- DateTimeOffset(DateTime.UtcNow + timespan)
cip.SlidingExpiration <- TimeSpan.Zero
cache.Add(ci, cip) |> ignore
result
| result ->
(result :?> 'a)
new Cached<'a>(newFunc, cache)

let cacheAsync timespan (func : string -> Async<'a>) =
let cache = new MemoryCache(typeof<'a>.FullName)
let newFunc parameter =
match cache.Get(parameter) with
| null ->
async {
let! result = func parameter
let ci = CacheItem(parameter, result :> obj)
let cip = CacheItemPolicy()
cip.AbsoluteExpiration <- DateTimeOffset(DateTime.UtcNow + timespan)
cip.SlidingExpiration <- TimeSpan.Zero
cache.Add(ci, cip) |> ignore
return result
}
| result ->
async { return (result :?> 'a) }
new Cached<Async<'a>>(newFunc, cache)

用法:

let getStuff = 
let cached = cacheAsync (TimeSpan(0, 0, 5)) uncachedGetStuff
// deal with the fact that the cache is IDisposable here
// however is appropriate...
cached.Func

如果您对直接访问底层缓存不感兴趣,显然您可以返回一个与旧函数具有相同签名的新函数 - 但考虑到缓存是 IDisposable,这似乎是不明智的。

我认为在很多方面我更喜欢你的解决方案,但是当我遇到类似的问题时,我有一个反常的想法,如果可以的话,我真的应该使用内置的东西。

关于f# - 是时候在 F# 中实现记忆化了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18215543/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com