C# 性能比较:检查并设置标志与仅设置标志

C# 性能比较:检查并设置标志与仅设置标志,c#,performance,C#,Performance,我有一个标志字典,通过每个事件,我设置了相关的标志。有些事件来自同一类型且具有相同的id,因此可以多次设置它们的标志。如果我在设置前检查一个标志,它会更快吗 Dictionary<int, bool> flags = new Dictionary<string, bool>(); foreach(var eventType in eventTypes) { flags.Add(eventType.id, false); } for (int i = 0; i &l

我有一个标志字典,通过每个事件,我设置了相关的标志。有些事件来自同一类型且具有相同的id,因此可以多次设置它们的标志。如果我在设置前检查一个标志,它会更快吗

Dictionary<int, bool> flags = new Dictionary<string, bool>();
foreach(var eventType in eventTypes)
{
    flags.Add(eventType.id, false);
}
for (int i = 0; i < iterations; i++)
{
    // resetting flags for current iteration.
    foreach(var k in flags.Keys)
    {
        flags[k] = false;
    }
    Event[] events = GetEvents();
    foreach(var e in events)
    {
        flags[e.id] = True; // Would it be better to check flag before set it?
    }
    // Do related works for events occurred 
}
Dictionary flags=newdictionary();
foreach(eventTypes中的var eventType)
{
flags.Add(eventType.id,false);
}
对于(int i=0;i
仅将标志设置为
false
(如果它们是
true
),速度较慢,因为您需要查询字典两次。
如果直接设置该标志,则它仅为一个操作

此外,如果您有一个多线程环境,您还需要通过在“check&set”逻辑周围放置一个
lock
来防止争用情况,这将使其速度进一步减慢


我能想到的进行检查的唯一原因是,如果您有一个自定义字典,它确实会在一个设置的事件上触发某些内容,即使它是相同的值,并且您希望避免这种情况。

在这种情况下,最昂贵的操作发生在您对字典进行索引时。每当您尝试添加、更新或读取特定密钥的值时,
字典
需要计算密钥的散列值,然后获取适当的bucket,然后迭代该bucket中的元素(如果存在多个doe到散列冲突),并将它们与密钥进行比较

如果在更新之前检查了该值,则需要执行两次,以防需要更改该值

另一方面,这正是获取字典中可能存在或不存在的值的首选(性能更高)方法的原因:因为调用
ContainsKey
,然后对字典进行索引将需要两个操作(或者更糟糕的是,捕获
KeyNotFoundException

此外,如果您的代码代码>键的范围有限,您可以考虑使用A而不是<代码>字典< /> >

[编辑]

您可以使用字典检查给定事件是否至少发生过一次。为此,您可以简单地编写:

var eventIds = new HashSet<string>(GetEvents().Select(e => e.Id));

在任何基于字典的操作中,查找时间都可能远远超过设置标志所需的时间,这通常只需要在内存中设置一个值

如果只设置标志而不进行检查,则只涉及一次查找

如果您首先检查,那么这可能涉及两个查找。但是,编译器很可能会将其优化为只进行一次查找,因此速度可能类似

结论:

  • 不检查可能更快,但这只有在编译器不擅长优化时才明显

  • <> >如果你真的关心性能,考虑你的应用程序中是否可以使用数组而不是字典,因为数组的速度会更快。p>

然而,这只是基于我的知识和直觉。如果您真的很重视性能,那么唯一真正的解决方案就是编写一些代码来测试各种方法的速度

为什么/为什么要检查该标志?@chrfin避免在设置之前设置标志。事件可以具有相同的id。对我来说,如果您在设置之前进行检查,您将有2个操作要完成。一张支票,然后一套。如果你只是设置了一个标志,你将只有一个。最坏的情况是,如果所有的标志都需要更改,您将有O(2n)。如果你没有支票,它将永远是O(n)。@Sergey:糟了,我还没有看来源。奇怪的是,他们没有选择重用现有的类,因为它似乎是一个非常类似的实现。对不起,我不明白你的第一句话,也不是想偷你的主意。我认为你的评论意味着OP应该在最后一个foreach之前过滤事件。在SAM告诉我更新我的答案后,我才意识到这是同样的事情,我真的开始打字了。无论如何,你应该把这个作为你的答案。@Groo没问题-这个答案对OP很有帮助,而且很好。无需复制某些内容:)
if (eventIds.Contains(id))
{
   // do something
}