Lazy<_> 和 thunk (fun () -> ...) 之间的实际区别
Practical differences between Lazy<_> and thunk (fun () -> ...)
在 F# 核心库中,有采用 thunk (fun () -> ...
) 的高阶函数,但在概念上也可以采用 Lazy<_>
,例如 Option.defaultWith
。 F# 通过 lazy
关键字对 Lazy<_>
提供了良好的语法支持,但我想不出 F# 核心库中有任何函数采用 Lazy<_>
而不是 thunk。我猜这是因为 "more FP" 使用 thunk 而不是 .NET 特定的 Lazy<_>
类型。
但除了模糊之外 "less FP":如果最多需要 1 次该值,那么使用 Lazy<_>
而不是 thunks 的实际考虑是什么?例如,是否存在性能差异 (CPU and/or allocations/memory)?其他问题? Lazy<_>
比 thunk 更能解决哪些情况?
作为包装 thunk 的单独对象,提供同步并保存结果引用,Lazy<_>
与简单的 thunk 相比有一些额外的开销。
如果您知道您只会(最多)评估一次 thunk,我认为如果可以的话您没有理由不使用函数。您可以在另一个函数中包装对 Lazy<_>
的 Value
的调用,但在这种情况下,据我所知它没有任何好处。
我记得 Lazy<_>
有用的一个场景是当我们在产品中有两个单独的功能标志时,如果启用,这两个功能标志都可能需要初始化 Orleankka actor 系统 - 昂贵的操作,每个应用程序只能执行一次启动。
所以我们的选项要么是很多嵌套的 if
s,可变选项,要么是这个:
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()
其他情况通常是当您不确定是否最多评估一次 thunk 时,尤其是当它可以同时发生时。我认为我们也有这样的用例,当没有在本地提供给同时启动的几个组件时读取一些外部配置 - Lazy<_>
确保我们只进行一次远程调用(如果需要的话),而不管哪个组件首先发现它需要它。
在 F# 核心库中,有采用 thunk (fun () -> ...
) 的高阶函数,但在概念上也可以采用 Lazy<_>
,例如 Option.defaultWith
。 F# 通过 lazy
关键字对 Lazy<_>
提供了良好的语法支持,但我想不出 F# 核心库中有任何函数采用 Lazy<_>
而不是 thunk。我猜这是因为 "more FP" 使用 thunk 而不是 .NET 特定的 Lazy<_>
类型。
但除了模糊之外 "less FP":如果最多需要 1 次该值,那么使用 Lazy<_>
而不是 thunks 的实际考虑是什么?例如,是否存在性能差异 (CPU and/or allocations/memory)?其他问题? Lazy<_>
比 thunk 更能解决哪些情况?
作为包装 thunk 的单独对象,提供同步并保存结果引用,Lazy<_>
与简单的 thunk 相比有一些额外的开销。
如果您知道您只会(最多)评估一次 thunk,我认为如果可以的话您没有理由不使用函数。您可以在另一个函数中包装对 Lazy<_>
的 Value
的调用,但在这种情况下,据我所知它没有任何好处。
我记得 Lazy<_>
有用的一个场景是当我们在产品中有两个单独的功能标志时,如果启用,这两个功能标志都可能需要初始化 Orleankka actor 系统 - 昂贵的操作,每个应用程序只能执行一次启动。
所以我们的选项要么是很多嵌套的 if
s,可变选项,要么是这个:
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()
其他情况通常是当您不确定是否最多评估一次 thunk 时,尤其是当它可以同时发生时。我认为我们也有这样的用例,当没有在本地提供给同时启动的几个组件时读取一些外部配置 - Lazy<_>
确保我们只进行一次远程调用(如果需要的话),而不管哪个组件首先发现它需要它。