Lazy <_>和thunk(fun()-> ...)之间的实际区别

时间:2018-12-12 12:13:59

标签: .net f# lazy-loading

在F#核心库中,有一些高阶函数会接受重排(fun () -> ...),但从概念上讲也可以接受Lazy<_>,例如Option.defaultWith。 F#通过Lazy<_>关键字对lazy具有良好的语法支持,但是我想不起来F#核心库中的任何函数都需要Lazy<_>而不是thunk。我猜这是因为使用thunk比使用.NET特定的Lazy<_>类型“更多的FP”。

但是除了模糊地“减少FP”之外:如果该值最多需要1次,那么使用Lazy<_>而不是thunk的实际考虑是什么?例如,是否存在性能差异(CPU和/或分配/内存)?还有其他问题吗?用Lazy<_>而不是笨拙可以更好地解决哪种情况?

1 个答案:

答案 0 :(得分:9)

作为一个单独的对象,它包装了thunk,提供了同步并保存了结果引用,与简单的thunk相比,Lazy<_>有一些额外的开销。

如果您知道(最多)只评估一次thunk,那么我认为没有理由不使用函数。您可以在另一个函数中包装对Lazy<_>的{​​{1}}的调用,但是在这种情况下,我没有任何好处。

我记得一个Value有用的情况是,我们的产品中有两个单独的功能标志,如果启用了这两个标志,都可能需要初始化Orleankka actor系统-昂贵的操作,每次应用程序启动时只能执行一次。

因此,我们的选项要么是很多嵌套的Lazy<_>,要么是可变的选项,要么是:

if

与thunk不同,let actorSystem = lazy initializeActorSystem () if feature1Enabled then let as = actorSystem.Value ... if feature2Enabled then let as = actorSystem.Value ... 还允许您检查thunk是否已评估。来自同一个实例:

Lazy<_>

通常情况下,如果您不确定一次最多可以评估一次thunk,尤其是可以同时发生的情况。我认为我们也有类似的用例,当未在本地同时提供给正在同时启动的多个组件时,可以读取一些外部配置-if actorSystem.IsValueCreated then actorSystem.Value.Dispose() 确保无论哪个组件,我们都只能进行一次远程调用(如果需要的话)首先发现它需要它。