只是一个快速查询:我有一段代码将一个字符串与一长串值进行比较,例如
if(str == "string1" || str == "string2" || str == "string3" || str == "string4". DoSomething();
代码清晰度和可维护性的兴趣我把它改成了
public static string[] strValues = { "String1", "String2", "String3", "String4"}; ... if(strValues.Contains(str) DoSomething();
只发现代码执行时间从2.5秒到6.8秒(执行大约200,000次).
我当然明白了一个轻微的表现权衡,但300%?
无论如何,我可以不同地定义静态字符串以提高性能?
干杯.
据透露..
使用:
private static HashSetstrHashSet = new HashSet () { "0string", "1string", "2string", "3string", "4string", "5string", "6string", "7string", "8string", "9string", "Astring", "Bstring" }; private static List strList = strHashSet.ToList(); private static string[] strArray = strList.ToArray(); private static Dictionary strHashDict = strHashSet.ToDictionary(h => h.GetHashCode()); private static Dictionary strDict = strHashSet.ToDictionary(h => h); // Only one test uses this method. private static bool ExistsInList(string str) { return strHashDict.ContainsKey(str.GetHashCode()); }
检查列表中的第一个和最后一个字符串,然后检查不在列表中的字符串:"xstring"执行500,000次迭代,所有时间都以毫秒为单位.
1.A Test: result = (str == "0string" || str == "1string" ... [storage var] [first]:[ last ]:[ none ]:[average] strArray 3.78 : 45.90 : 57.77 : 35.82 2.A Test: ExistsInList(string); [storage var] [first]:[ last ]:[ none ]:[average] none 36.14 : 28.97 : 24.02 : 29.71 3.A Test: .ContainsKey(string.GetHashCode()); [storage var] [first]:[ last ]:[ none ]:[average] strHashDict 34.86 : 28.41 : 21.46 : 28.24 4.A Test: .ContainsKey(string); [storage var] [first]:[ last ]:[ none ]:[average] strDict 38.99 : 32.34 : 22.75 : 31.36 5.A Test: .Contains(string); [storage var] [first]:[ last ]:[ none ]:[average] strHashSet 39.54 : 34.78 : 24.17 : 32.83 strList 23.36 : 122.07 : 127.38 : 90.94 strArray 350.34 : 426.29 : 426.05 : 400.90 6.A Test: .Any(p => p == string); [storage var] [first]:[ last ]:[ none ]:[average] strHashSet 75.70 : 331.38 : 339.40 : 248.82 strList 72.51 : 305.00 : 319.29 : 232.26 strArray 38.49 : 213.63 : 227.13 : 159.75
当我们更改列表中的字符串时,会产生有趣的(如果不是意外的)结果:
private static HashSetstrHashSet = new HashSet () { "string00", "string01", "string02", "string03", "string04", "string05", "string06", "string07", "string08", "string09", "string10", "string11" };
用"string99"作为无检查.
1.B Test: result = (str == "string00" || str == "string01" ... [storage var] [first]:[ last ]:[ none ]:[average] strArray 85.45 : 87.06 : 91.82 : 88.11 2.B Test: ExistsInList(string); [storage var] [first]:[ last ]:[ none ]:[average] none 30.12 : 27.97 : 21.36 : 26.48 3.B Test: .ContainsKey(string.GetHashCode()); [storage var] [first]:[ last ]:[ none ]:[average] strHashDict 32.51 : 28.00 : 20.83 : 27.11 4.B Test: .ContainsKey(string); [storage var] [first]:[ last ]:[ none ]:[average] strDict 36.45 : 32.13 : 22.39 : 30.32 5.B Test: .Contains(string); [storage var] [first]:[ last ]:[ none ]:[average] strHashSet 37.29 : 34.33 : 23.56 : 31.73 strList 23.34 : 147.75 : 153.04 : 108.04 strArray 349.62 : 460.19 : 459.99 : 423.26 6.B Test: .Any(p => p == string); [storage var] [first]:[ last ]:[ none ]:[average] strHashSet 76.26 : 355.09 : 361.31 : 264.22 strList 70.20 : 332.33 : 341.79 : 248.11 strArray 37.23 : 234.70 : 251.81 : 174.58
对于案例A和B看起来像测试2和3具有优势.
但是,HashSet.Contains(字符串)非常高效,不受列表内容的影响,并且具有清晰的语法......可能是最佳选择.
是的,这是真的,我没有生命.
您尝试过的两种方法都具有O(n)性能,因此当您添加更多字符串时它们会变慢.如果您使用的是.NET 3.5或更高版本,那么您可以尝试使用HashSet
替代版本并在应用程序开始时将其初始化一次.然后,您可以获得大约O(1)个查找.
对于.NET v2.0,您可以HashSet
使用a 来模拟a Dictionary
并使用ContainsKey
而不使用该值.
你在生产代码中实际运行了200,000次吗?如果是这样,您可能希望将哈希检查视为更快的否定检查.
如果200,000次只是为了说明差异,那我就不用担心了.它的时间仅增加0.02毫秒.
Contains
比测试静态字符串更通用,因此存在少量开销.除非这个代码是Mark提到的瓶颈,否则不值得优化.CS中有一句名言:"过早优化是所有邪恶的根源." 报价不太准确,但它提醒了最终的优化指南:先测量.