【问题标题】:Optimize Dictionary Add on ExpandoObjects in C#在 C# 中的 ExpandoObjects 上优化字典添加
【发布时间】:2012-08-29 10:39:46
【问题描述】:

我有一个高级程序,它从数据库中检索数据并通过 C# 中的 ExpandoObjects 从数据中创建对象。

我现在正在优化我的整个流程,但遇到了一段代码,这在性能方面是瓶颈。我很好奇我可以在多大程度上进一步优化这段代码,并且已经通过执行以下操作将其运行速度提高了 3 倍:

  • 在单独的 for 循环中分隔“查找“类型”部分”,并且仅在尚未初始化时对其进行迭代。
  • 添加了当值为 null 时创建一个空字符串的情况,因为由于某种原因 Dictionary.Add 在添加 Null 值时会减慢很多。

        // Holds all objects that are created inside the object.
        Dictionary<string, IDictionary<string, dynamic>> objects = new Dictionary<string, IDictionary<string, dynamic>>();
    
        // This foreach loop is the slowest part!
        foreach (KeyValuePair<string, dynamic> pair in fields)
        {
            string type = pair.Key.Split('_')[0];
    
            IDictionary<string, dynamic> obj;
            if (!objects.TryGetValue(type, out obj))
            {
                obj = new ExpandoObject();
                objects.Add(type, obj);
            }
            int location = pair.Key.IndexOf(type + "_");
            string key = pair.Key.Remove(location, type.Length + 1);
            if (pair.Value == null)         // If Value is null, replace it with an empty string (dictionary slows quite alot when passing it null values)
                obj.Add(key, "");
            else
                obj.Add(key, pair.Value);         
        }
    
        if (types == null)
            types = objects.Select(x => x.Key).ToList();
    

我想知道,为什么字典在添加 Null 值时会减慢这么多,是在底层结构中遇到空值时它会执行特殊操作吗?还有什么我缺少的东西可以进一步优化代码吗?

再次非常感谢任何帮助。


更新
  • 使用我从 SO 收集的最新更改编辑了代码。

【问题讨论】:

  • 请注意,您的编辑并未获得我建议的所有更改。你错过了循环结束时的重要部分:obj.Add 而不是 objects[type].Add
  • @DanielHilgarth,你是对的!我一定错过了,对不起:)。我再次编辑了帖子。

标签: c# .net optimization dictionary add


【解决方案1】:

您可以通过使用TryGetValue 而不是ContainsKey 来避免在字典中进行多次查找:

foreach (KeyValuePair<string, dynamic> pair in fields) 
{ 
    string type = pair.Key.Split('_')[0]; 

    IDictionary<string, dynamic> obj;
    if (!objects.TryGetValue(type, out obj)) 
    { 
        obj = new ExpandoObject(); 
        objects.Add(type, obj); 
    } 
    int location = pair.Key.IndexOf(type + "_"); 
    string key = pair.Key.Remove(location, type.Length + 1); 
    if (pair.Value == null)
        obj.Add(key, ""); 
    else 
        obj.Add(key, pair.Value);            
} 

顺便说一句:我没有看到你在第二个 foreach 循环中使用 types。因此,您可以用这个简单的代码替换 first foreach 循环:

types = objects.Select(x => x.Key).ToList();

这应该会节省很多时间,因为它消除了在 types 列表中的缓慢搜索和类型的双重解析。

显然这需要放在我上面显示的foreach 循环之后。

【讨论】:

  • 谢谢。速度并没有太大的提高,但肯定清理了代码! :)
  • 会在 100 - 500 之间变化,在我的测试用例中是 283
  • @JoeyDewd:好的。比你现在应该停止优化。这是微优化,不值得努力。
  • 好的,感谢您发布的建议和解决方案!我会等待一些进一步的想法/笔记,很可能会接受你的回答:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-02
  • 1970-01-01
相关资源
最近更新 更多