【发布时间】:2012-03-22 15:57:04
【问题描述】:
我想尽可能避免不必要的代码重复。在下面描述的场景中,我使用了Action 委托来避免代码重复。但是,当使用Action 委托方法时,代码会变慢大约 50%-80%。
从性能的角度来看,有没有比Action 委托更有效的方法来避免下面描述的场景中的代码重复?
除了长循环的最里面的语句之外,我有两种等效的方法:
public T[] MethodA<T>(T[] from)
{
...
for (var i = 0; i < len; ++i)
{
var j = GetIndex(i);
to[j] = from[i]; // This statement differs in MethodA and MethodB
}
...
return to;
}
public T[] MethodB<T>(T[] from)
{
...
for (var i = 0; i < len; ++i)
{
var j = GetIndex(i);
to[i] = from[j]; // This statement differs in MethodA and MethodB
}
...
return to;
}
为了避免代码重复,我实现了一个辅助方法,该方法采用Action 委托。调用委托会替换变量语句,如下所示:
private T[] HelperMethod<T>(T[], Action<T[], T[], int, int> action)
{
...
for (var i = 0; i < len; ++i)
{
var j = GetIndex(i);
action(from, to, i, j); // Invoke the Action delegate
}
...
return to;
}
那么我可以将MethodA和MethodB减少如下:
public T[] MethodA<T>(T[] from)
{
return HelperMethod(from, (src, dest, src_idx, dest_idx) => dest[dest_idx] = src[src_idx]);
}
public T[] MethodB<T>(T[] from)
{
return HelperMethod(from, (src, dest, dest_idx, src_idx) => dest[dest_idx] = src[src_idx]);
}
请注意,重构后的MethodA 和MethodB 之间的唯一区别是HelperMethod 调用的Action 签名中src_idx 和dest_idx 的顺序。
【问题讨论】:
-
您是如何衡量 50-80% 的性能下降的?听起来不太可能
-
我在重构前后的单元测试中进行了时序比较。当然,上面的代码是我实现的简化版本,但在重构之前经过的时间(使用单元测试中的 Stopwatch 类测量)是 1.6-1.8 秒,而在重构之后经过的时间是 2.6-2.7 秒。跨度>
-
它不太可能通过任何形式的函数调用来击败直接分配 - 因此,如果它对性能至关重要,那么您已经有了适合您的解决方案......
-
是的,你说得对,阿列克谢,谢谢。在受 democodemonkey 下面的响应启发的进一步测试之后,幸运的是,在循环内测试布尔值非常便宜,所以我的解决方案是坚持直接分配,在循环的每次迭代中都会测试分配路线。跨度>
-
循环是否与编写的完全一致,或者您错过了更多代码?您可以将
if移动到循环之外,然后复制循环的内容......有点中间立场。
标签: c# delegates refactoring code-duplication