【发布时间】:2019-05-25 04:53:10
【问题描述】:
我的服务器上的 RAM 数量有限,但我需要在控制台程序的内存中处理大量数据。是否有任何技巧可以让我仍然获得相同的最终结果,但不需要那么多 RAM
对于这个例子,我在一个字符串列表中有 1 亿个电子邮件地址。我需要找出我与之比较的任何新电子邮件是否已经存在。如果是这样,请添加它们。如果没有,请不要添加它们。所以我们总是有一个唯一的电子邮件列表,没有重复。
在此示例中,1 亿封电子邮件需要大约 17GB 的 RAM。
您是否知道任何技巧或技巧可以减少所需的 RAM 量以至少仍然能够执行“它是否存在于列表集合中?”比较? - 想到的示例类型:例如不同类型的集合,或自定义的第三方引用的软件工具,可压缩内存中的数据,但您仍然可以对该数据进行排序或比较,或者可能是基于文件的数据库系统,它使用相同数量的数据上的内存要少得多。
我编写了代码来演示如何以正常方式执行此操作,从而消耗 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 降低到更小。
【问题讨论】:
-
你可以使用数据库。
-
或者,从排序列表中工作。然后你的内存需求下降到 O(1)。
-
数据库 + 电子邮件地址索引 = 内存使用量小,查找速度快。请解释为什么列表需要在内存中而不是这样做。或者只是向您的服务器添加另外 32 GB 的 RAM :)
-
如果您仍在使用内存路由,您还可以考虑使用 UTF-8 编码存储字符串,这应该可以对大多数存储地址进行 2:1 压缩,因为将编码许多字符如果使用默认 (UTF-16) 编码,则为单个字节而不是 16 位。
-
是否有特定的 NFR 要求您在内存中执行此操作?显而易见的答案是使用数据库。如果这还不够快,请使用更大的数据库服务器。如果这还不够快,请使用数据库集群。
标签: c# memory-management out-of-memory