Skip to main content
 首页 » 编程设计

c#之当需要处理大量内存集合时,有什么技巧可以减少内存消耗吗

2024年02月04日33me-sa

我的服务器上的 RAM 数量有限,但我需要在控制台程序的内存中处理大量数据。是否有任何技巧可以让我仍然获得相同的最终结果,但不需要那么多 RAM

对于这个例子,我在一个字符串列表中有 1 亿个电子邮件地址。我需要查明我正在与之比较的任何新电子邮件是否已经存在于其中。如果是这样,请添加它们。如果没有,请不要添加它们。所以我们总是有一个唯一的电子邮件列表,没有重复。

此示例中的 1 亿封电子邮件需要大约 17GB 的 RAM。

您是否知道任何技巧或提示来减少至少仍然能够执行“它是否存在于列表集合中?”所需的 RAM 量?比较? - 想到的示例类型:例如不同类型的集合,或自定义第 3 方引用的软件工具,它压缩内存中的数据但您仍然可以对该数据进行排序或比较,或者可能是基于文件的数据库系统使用相同数据量的内存要少得多。

我已经编写了代码来演示如何以导致消耗 17GB RAM 的正常方式执行此操作。

using System; 
using System.Collections.Generic; 
using System.Linq; 
 
namespace NewProgram 
{ 
    class Program 
    { 
        public static List<string> emails = new List<string>();  
 
        public static void Main(string[] args) 
        { 
            LoadAllEmails(); 
 
            Console.WriteLine(emails.Count() + " total emails"); //100000000 total emails 
 
            AddEmailsThatDontExistInMasterList( 
                new List<string>() 
                { 
                "something@test.com", //does not already exist, so it will be added to list 
                "testingfirst.testinglast"+ (1234567).ToString() + "@testingdomain.com", //should already exist, won't be added 
                "testingfirst.testinglast"+ (3333335).ToString() + "@testingdomain.com", //should already exist, won't be added 
                "something2@test.com", //does not already exist, so it will be added to list 
                "testingfirst.testinglast"+ (8765432).ToString() + "@testingdomain.com", //should already exist, won't be added 
                }); 
 
            Console.WriteLine(emails.Count() + " total emails after"); //100000002 total emails 
 
            Console.ReadLine(); 
        } 
 
 
        public static void LoadAllEmails() 
        { 
            for (int i = 0; i < 100000000; i++)  //100,000,000 emails = approximately 17GB of memory 
            { 
                emails.Add("testingfirst.testinglast" + i.ToString() + "@testingdomain.com"); 
            } 
        } 
 
        public static void AddEmailsThatDontExistInMasterList(List<string> newEmails) 
        { 
            foreach (string email in newEmails) 
            { 
                if (emails.Contains(email) == false) 
                { 
                    emails.Add(email); 
                } 
            } 
        } 
    } 
} 

将 100,000,000 封电子邮件添加到“电子邮件”集合后,它将在添加到其中的新列表中查看另外 5 封电子邮件。将添加 2 个,不会添加 3 个,因为它们已经在列表中重复。完成后,集合中的电子邮件总数为 100,000,002 封。这只是为了证明我的最终目标是能够与现有集合进行比较,以查看某个值是否重复或已经存在于该集合中,这是一个非常大的数据集合。另一个目标是将总消耗的 RAM 从 17 GB 降低到更小的数量。

请您参考如下方法:

选项 1 使用三叉树

这种数据结构是一种在内存中存储单词的有效方式。它高度压缩且搜索速度快。

选项 2 使用内存哈希和磁盘文件

在内存中只保留每封电子邮件的哈希值。如果您在哈希表中得到命中,请查看磁盘。

选项 3 使用布隆过滤器和磁盘文件

参见 https://llimllib.github.io/bloomfilter-tutorial/