0

我正在寻找一种分析自定义日志文件的方法。

我现在已经使用 LINQ 和 C#.NET 实现了。它仅适用于最大 500MB 的日志文件。

日志文件的每一行都被制成一个看起来像的对象

public class Metrics
{
    public DateTime Date { get; set; }
    public string Metrics1 { get; set; }
    public string Metrics2 { get; set; }
                :
                :
    public string Metrics9 { get; set; }
}

List<Metrics> MetricsList = new List<Metrics>();

MetricsList 已填充。在 MetricsList 上运行各种 LINQ 查询以提供有用的分析。据观察,一个 Metrics 对象需要 300 个字节。我在 500MB 的日志文件中有大约 400 万行,这使得仅 MetricsList 的大小就消耗了超过 1GB 的程序内存。

我的要求是解析和分析大小高达 2 GB 的文件,这看起来会消耗 4 GB 的内存。

使用 Windows、Microsoft 技术和任何开源库的任何更好的方法或替代方案。

4

2 回答 2

1

通常您不想将这样的文件存储在内存中(当然除非您有足够的内存),而是在解析文件时处理数据。我只需安装更多内存并将解决方案设置为 64 位可能...

但是,如果这不是一个选项,您总是可以稍微优化内存使用。.NET 将字符串存储为 char[] ,其中 char 基本上是 2 字节短。您可以通过使用 Encoding.UTF8.GetBytes 简单地将其存储为 char[] 而不是 byte[] 来轻松节省大量内存。

此外,在 64 位环境中,每个字符串或 byte[] 消耗 24 个字节(16 个用于对象本身,8 个用于指针)。如果你有很多小字符串,那可以加起来。除了将它们存储为字符串之外,您还可以存储单个 byte[] 并在 getter 中进行解析。

所以总结我的建议是:购买更多内存或在您阅读/需要时处理数据。

[更新+1]

刚刚注意到您使用了一个列表。随用随处理的最简单方法是将文件读取为 IEnumerable 并在其上使用 Linq。不要先把它放在一个列表中。例如:

public IEnumerable<Metric> ReadFile()
{
    string s;
    while ((s=myFileReader.ReadLine())!=null)
    {
        yield return Parse(s);
    }
}

int someAnalysis = ReadFile().Sum((a)=>(a.Metric1.Length)); // or whatever you do

[更新+2]

哦,我还有一个技巧要给你。读取文件可能会影响性能,因为文件 IO 相对来说很糟糕。因此,除了使用上面的 IEnumeration 技巧,您还可以使用压缩流将所有数据存储在内存中 - 然后在处理期间使用它而不是文件。

对于那些想知道我是否认真对待这个奇怪的解决方案的人:这是构建搜索技术和数据库时经常使用的技术,仅仅是因为拥有更多(快速)内存意味着拥有更少(慢)磁盘 IO。此外,日志文件可能会很好地压缩。

因此,在内存流之上读取文件 && flatestream。然后以上面讨论的方式为 Linq 阅读它(再次,在 memorystream 之上的 flatestream)。

于 2013-01-18T13:06:21.540 回答
1

我使用 SQlite 完成了类似的任务。安装 System.Data.SQLite NuGet(可选:我也使用 Dapper NuGet 作为一个非常有效的微 ORM),然后你就有了一个非常好的工具来执行查询和生成你的报告。您可能不喜欢的唯一一件事是您必须编写 SQL 而不是 LINQ(虽然 SQLite 也有 LINQ;但我没有使用它)。

这样,内存消耗也会消失。

于 2013-01-18T13:15:33.100 回答