我有一个Vector2的Generated列表。我必须对照字典检查它们是否存在,这个函数每次都会执行。
这样做哪个跑得最快/更好?
public static bool exists(Vector2 Position, Dictionary<Vector2, object> ToCheck)
{
try
{
object Test = ToCheck[Position];
return (true);
}
catch
{
return (false);
}
}
还是我应该坚持规范?
public static bool exists(Vector2 Position, Dictionary<Vector2, object> ToCheck)
{
if (ToCheck.ContainsKey(Position))
{
return (true);
}
return (false);
}
感谢您的输入:)
旁注:(密钥的值在这一点上无关紧要,否则我会使用TryGetValue而不是ContainsKey)
我知道这是一个老问题,但只是添加一些经验数据。。。
在一本有10000个词条的词典上运行50000000次查找,并比较完成的相对时间:
如果每次查找都成功:
- 直接(未检查)跑步需要1.2秒
- 有防护的(ContainsKey)跑步需要2秒
- 一次有把握的(尝试接球)跑需要1.21秒
。。如果每10000次查找中就有1次失败:
- 一次有保护的(ContainsKey)跑步需要2秒
- 一次有把握的(尝试接球)跑需要1.37秒
。。如果每10000次查找中有16次失败:
- 一次有保护的(ContainsKey)跑步需要2秒
- 一次有把握的(尝试接球)跑需要3.27秒
。。如果每10000次查找中有250次失败:
- 一次有保护的(ContainsKey)跑步需要2秒
- 一次有把握的(尝试接球)跑需要32秒
。。因此,有保护的测试将增加恒定的开销,而try-catch测试的运行速度几乎与没有测试一样快(如果它从未失败),但会随着失败次数的增加而降低性能。
我用来运行测试的代码:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{ Test(0);
Test(1);
Test(16);
Test(250);
}
private static void Test(int failsPerSet)
{ Dictionary<int, bool> items = new Dictionary<int,bool>();
for(int i = 0; i < 10000; i++)
if(i >= failsPerSet)
items[i] = true;
if(failsPerSet == 0)
RawLookup(items, failsPerSet);
GuardedLookup(items, failsPerSet);
CaughtLookup(items, failsPerSet);
}
private static void RawLookup
( Dictionary<int, bool> items
, int failsPerSet
){ int found = 0;
DateTime start ;
Console.Write("Raw (");
Console.Write(failsPerSet);
Console.Write("): ");
start = DateTime.Now;
for(int i = 0; i < 50000000; i++)
{ int pick = i % 10000;
if(items[pick])
found++;
}
Console.WriteLine(DateTime.Now - start);
}
private static void GuardedLookup
( Dictionary<int, bool> items
, int failsPerSet
){ int found = 0;
DateTime start ;
Console.Write("Guarded (");
Console.Write(failsPerSet);
Console.Write("): ");
start = DateTime.Now;
for(int i = 0; i < 50000000; i++)
{ int pick = i % 10000;
if(items.ContainsKey(pick))
if(items[pick])
found++;
}
Console.WriteLine(DateTime.Now - start);
}
private static void CaughtLookup
( Dictionary<int, bool> items
, int failsPerSet
){ int found = 0;
DateTime start ;
Console.Write("Caught (");
Console.Write(failsPerSet);
Console.Write("): ");
start = DateTime.Now;
for(int i = 0; i < 50000000; i++)
{ int pick = i % 10000;
try
{ if(items[pick])
found++;
}
catch
{
}
}
Console.WriteLine(DateTime.Now - start);
}
}
}
一定要使用ContainsKey
检查;异常处理可能会增加很大的开销。
引发异常会对性能产生负面影响。对于经常失败的代码,可以使用设计模式来最大限度地减少性能问题。
异常不适用于您可以检查的条件。
我建议阅读MSDN文档中关于异常的一般内容,尤其是关于异常处理的内容。
永远不要将try/catch作为常规程序路径的一部分。它确实很昂贵,而且应该只捕获无法防止的错误。ContainsKey是去这里的路。
旁注:不,你不会的。如果值很重要,请使用ContainsKey检查它是否存在,如果存在,则检索它。不要尝试/抓住。
旁注:(密钥的值在这一点上无关紧要,否则我会使用TryGetValue而不是ContainsKey)
您接受的答案是正确的,但补充一下,如果您只关心密钥而不关心值,那么您可能正在寻找HashSet
而不是Dictionary
?
此外,您的第二个代码片段是一个添加零值的方法。只需使用ToCheck.ContainsKey(Position)
,不要生成一个只调用该方法并返回其值但不执行其他操作的方法。