Bri*_*don 1 c# extension-methods profiling
我编写了以下扩展方法来从字典中获取元素,如果键不存在则写入null:
public static TValue ItemOrNull<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
{
try
{
return dict[key];
}
catch (KeyNotFoundException ex)
{
return default(TValue);
}
}
Run Code Online (Sandbox Code Playgroud)
我注意到我的程序运行得非常慢,所以我使用高精度计时器类跟踪了这个扩展方法的问题.我得到了类似的结果〜连续100次:
DebugTimer.ResetTimer();
dict1.ItemOrNull(key);
dict2.ItemOrNull(key);
DebugTimer.StopTimer();
Run Code Online (Sandbox Code Playgroud)
需要大约110,000,000个刻度(我的处理器超过0.03秒).虽然更详细的版本:
DebugTimer.ResetTimer();
if (dict1.ContainsKey(key))
y = dict1[key];
if (dict2.ContainsKey(key))
z = dict2[key];
DebugTimer.StopTimer();
MessageBox.Show(y.ToString(), z.ToString()) // so the compiler doesn't optimize away y and z
Run Code Online (Sandbox Code Playgroud)
需要大约6,000个滴答(小于0.000002秒).
为什么我的扩展方法版本比冗长的版本花费的时间长4个数量级,这是否清楚?
Jon*_*eet 15
不要捕获流量控制的异常 - 它不仅仅会导致性能问题(尽管它们并不像大多数人想象的那么糟糕 - 正如Eric所说,大多数人对异常性能的恐惧来自使用调试器).它更多的是关于异常的逻辑性质.就个人而言,即使它们基本上是免费的,我也不会以这种方式使用例外.
这里有什么不好的事吗?对于用户要求此密钥值的任何方式都无效吗?绝对不是 - 该方法的全部目的是提供默认值.密钥缺失并不是特例 - 所以你应该寻找一种无异常的工作方式.
现在Dictionary<,>已经有了一种方法可以让你在密钥存在时获取一个值,并让你知道它是否被找到:TryGetValue.
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dict,
TKey key)
{
TValue ret;
// We don't care about the return value - we want default(TValue)
// if it returns false anyway!
dict.TryGetValue(key, out ret);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
扩展方法只是编译成常规静态方法调用,因此它们没有性能差异.
您可能还想添加一个重载,允许用户在未找到密钥时表示要返回的默认值:
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dict,
TKey key, TValue defaultValue)
{
TValue ret;
return dict.TryGetValue(key, out value) ? ret : defaultValue;
}
Run Code Online (Sandbox Code Playgroud)
TryGetValue顺便说一句,我已经调整了你的方法的名称来匹配.显然你不必遵循它 - 这只是一个建议.
| 归档时间: |
|
| 查看次数: |
1087 次 |
| 最近记录: |