C#:内存高效搜索 200 万个对象,无需外部依赖

Seb*_*son 10 c# optimization performance memory-management in-memory

我需要能够在 C# 中搜索大约 200 万个项目的集合。应该可以在多个字段上进行搜索。简单的字符串匹配就足够了。

使用像数据库这样的外部依赖不是一种选择,但使用内存数据库就可以了。

主要目标是做到这一点内存高效

集合中的类型非常简单,没有长字符串:

public class Item
{
    public string Name { get; set; } // Around 50 chars
    public string Category { get; set; } // Around 20 chars
    public bool IsActive { get; set; }
    public DateTimeOffset CreatedAt { get; set; }
    public IReadOnlyList<string> Tags { get; set; } // 2-3 items
}
Run Code Online (Sandbox Code Playgroud)

重点和要求

明确重点和要求:

  • 没有外部依赖(如数据库)
  • 内存高效(200 万个项目低于 2 GB)
  • 集合中的可搜索项目(必须是高性能的)

今天的非最优解

使用简单List<T>的上述类型,无论是作为 aclass还是 a struct,仍然需要大约 2 GB 的内存。

有没有更好的办法?

l33*_*33t 6

类中最重要的内存占用是使用只读列表。去掉它,你会减少大约 60% 的内存占用(用三个标签测试):

public class Item
{
    public string Name { get; set; }
    public string Category { get; set; }
    public bool IsActive { get; set; }
    public DateTimeOffset CreatedAt { get; set; }
    public string Tags { get; set; } // Semi-colon separated
}
Run Code Online (Sandbox Code Playgroud)

另外,请考虑使用DateTime代替DateTimeOffset. 这将进一步减少大约 10% 的内存占用。


小智 1

你可以做这些点,然后你就会看到是否有问题:


您是否需要改变属性,或者只是在集合中搜索对象?

如果您只是想进行研究,并且您的属性经常重复出现,那么您可以让一个属性被许多对象使用。

这样,值只存储一次,对象只存储引用。

仅当您不想改变属性时才可以执行此操作。

例如,如果两个对象具有相同的类别:

public class Category
{
    public string Value { get; }

    public Category(string category)
    {
        Value = category;
    }
}

public class Item
{
    public string Name { get; set; }
    public Category Category { get; set; }
    public bool IsActive { get; set; }
    public DateTimeOffset CreatedAt { get; set; }
    public IReadOnlyList<string> Tags { get; set; }
}


class Program
{
    public void Init()
    {
        Category category = new Category("categoryX");

        var obj1 = new Item
        {
            Category = category
        };

        var obj2 = new Item
        {
            Category = category
        };
    }
}
Run Code Online (Sandbox Code Playgroud)