通过直通回调参数传递状态或通过闭包捕获状态是否有技术原因?
Is there a technical reason to pass state via a pass-thru callback argument, or capture it via a closure?
昨晚在审查代码时,我发现了这段代码。值得注意的是,state
是通过执行泛型回调操作的 lambda 捕获的。
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
// Use capture-semantics for state
currentContext.Post(_ => callback(state), null);
else{
callback(state);
}
}
Post
然而,原生支持state
的pass-thru,所以上面也可以改写成这样...
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
// Use pass-thru state, not 'capture'
currentContext.Post(passedBackState => callback((TState)passedBackState), state);
else{
callback(state);
}
}
我的问题很简单...在这个特定的用例中,回调定义在与需要传递给它的状态相同的范围内,是否有任何 技术 使用捕获语义(第一个)而不是直通(第二个)的好处 and/or 缺点?我个人喜欢第一个,因为只有一个变量,但我问的是 技术上的 差异,如果两者似乎都有效的话。
闭包在堆上分配一个需要进行垃圾回收的新对象。通过状态参数传递数据不分配(除非数据是需要装箱的值类型)。
这些分配会叠加在频繁使用的方法或长期存在的进程(如 Web 应用程序)上,导致垃圾处理和延迟的 CPU 周期浪费。积极删除此类分配是 .NET Core 比 .NET Old 快得多的原因之一。
像 Roslyn Heap Allocation Analyzer 这样的 Roslyn 分析器突出显示了诸如装箱值类型、闭包、使用 params
数组等隐式分配。
更新
Rider 的 Dynamic Program Analysis 还突出显示了由于闭包、装箱、枚举器等引起的分配
昨晚在审查代码时,我发现了这段代码。值得注意的是,state
是通过执行泛型回调操作的 lambda 捕获的。
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
// Use capture-semantics for state
currentContext.Post(_ => callback(state), null);
else{
callback(state);
}
}
Post
然而,原生支持state
的pass-thru,所以上面也可以改写成这样...
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
// Use pass-thru state, not 'capture'
currentContext.Post(passedBackState => callback((TState)passedBackState), state);
else{
callback(state);
}
}
我的问题很简单...在这个特定的用例中,回调定义在与需要传递给它的状态相同的范围内,是否有任何 技术 使用捕获语义(第一个)而不是直通(第二个)的好处 and/or 缺点?我个人喜欢第一个,因为只有一个变量,但我问的是 技术上的 差异,如果两者似乎都有效的话。
闭包在堆上分配一个需要进行垃圾回收的新对象。通过状态参数传递数据不分配(除非数据是需要装箱的值类型)。
这些分配会叠加在频繁使用的方法或长期存在的进程(如 Web 应用程序)上,导致垃圾处理和延迟的 CPU 周期浪费。积极删除此类分配是 .NET Core 比 .NET Old 快得多的原因之一。
像 Roslyn Heap Allocation Analyzer 这样的 Roslyn 分析器突出显示了诸如装箱值类型、闭包、使用 params
数组等隐式分配。
更新
Rider 的 Dynamic Program Analysis 还突出显示了由于闭包、装箱、枚举器等引起的分配