【问题标题】:.Net Core vs .NET Framework performance issue.Net Core 与 .NET Framework 性能问题
【发布时间】:2019-01-02 12:17:57
【问题描述】:

我有一个 .NET Core 类库(我们称之为 Core),我想使用 WPF GUI 来使用它的一些功能。但与 .NET Core 相比,.NET 似乎非常慢。例如,我想运行以下方法:

private static void LoadData()
{
    Stopwatch w = new Stopwatch();


    List<BookingRecord> records = new List<BookingRecord>();
    w.Start();
    string csv = File.ReadAllText("/BookingData/Booking_Data - Copy.csv");

    Console.WriteLine(w.Elapsed);
    w.Restart();

    var lines = csv.Split('\n');

    foreach(var line in lines.Skip(1))
    {
        var data = line.Split(';');

        records.Add(new BookingRecord()
        {
            Origin = data[2],
            Destination = data[3],
            FlightDate = DateTime.Parse(data[4], new CultureInfo("De-de").DateTimeFormat),
            PassengersNumber = int.Parse(data[9])
        });
    }

    Console.WriteLine(w.Elapsed);
    w.Stop();
}

为此,我使用了两个控制台应用程序,一个在 .NET Core 下,一个在 .NET Framework 下。在.NET Core 下构建BookingData 列表的时间是0.4s,而在.NET Framework 的情况下大约是10s,这是有问题的,因为我将加载大约200 万行及以上的较大文件(客户端要求)。

那么有什么办法可以解决这个问题吗?目标是提供一个显示核心库结果的 GUI。

编辑

上面的sn -p只是为了提供MCVE,否则我在CsvHelper的帮助下使用StreamReader读取文件,边读边构建。

编辑 2

数据的加载和构建是在Core库内部构建的,也就是说使用.NET Core、WPF或.NET Framework项目一般,只是引用Core库并使用它的方法,它只是一个显示工具.为什么它必须产生与将代码移动到 .NET 项目时相同的结果?

【问题讨论】:

  • 是的,.Net 比 .Net Core 慢,但是您读取文件的方式一开始就不是很高效。作为第一步,您应该尝试使用 StreamReader 并逐行读取文件,而不是将整个文件读入内存。
  • @Compufreak,谢谢,是的,我正在使用 StreamReader 并逐行阅读和构建,问题中包含的代码只是为了提供 MCVE。
  • 上面的代码不是 MCVE。它不完整,因此无法验证。我创建了一个测试应用程序,它使用此处的“10,000”文件:sample-videos.com/download-sample-csv.php 和此代码:pastebin.com/T3cipQZJ,当在核心/框架上运行时,时间非常相似:00:00:00.0285065 到 00:00:00.0621625核心,00:00:00.0350395 到 00:00:00.0421969 用于框架。原始结果:pastebin.com/q9eHm7Vj
  • @AndyJ,我认为它已经完成,我只运行提供的方法,而且我无法产生与您的解决方案相同的结果。话虽如此,正如我在 EDIT 2 中所问的那样。当我在 .NET Framework 中从 .NET Core 引用 dll 时,它不应该使用 .NET Core 性能吗?
  • MCVE 在此处定义:stackoverflow.com/help/mcve“完成 - 提供重现问题所需的所有部分”。使用您提供的代码无法重现该问题。它没有BookingRecord,也没有你正在加载的数据文件。

标签: c# .net performance .net-core


【解决方案1】:

MS 说您应该使用 .Net Core 的主要原因之一是性能提升。谷歌搜索似乎证实了这一点。

但是,无论您使用哪个平台,如果您使用某种缓冲读取器一次读取一行文件,您可能会看到更好的性能,并且肯定会更好地利用内存。使用 ReadAllText 将尝试一次将所有 200 万行加载到内存中。如果您所做的只是按照它们在文件中出现的顺序处理每一行,那么这不是必需的。

【讨论】:

    【解决方案2】:

    在阅读完这些行后尝试移动列表创建:

    var lines = csv.Split('\n');
    var records = new List<BookingRecord>(lines.Length);
    

    这应该会产生巨大的差异。在您的版本中,它将从一个包含 8 个项目的底层数组开始,当它已满时,创建一个新的 16 个项目并复制旧的,当它已满时,创建一个包含 32 个项目的底层数组并复制 16 个,等等.

    将其初始化为正确的大小可以防止这种情况发生。也许 Core 已经能够以更智能的方式做到这一点。它应该会明显更快,尽管 25 倍的系数似乎表明这里还有其他东西在起作用。

    如果将记录设为结构而不是类,则速度会更快,因为它可以一次性保留整个内存块,而不是每条记录的一小部分。

    【讨论】:

    • List&lt;BookingRecord&gt; records = new List&lt;BookingRecord&gt;(); 甚至不包括在测量时间中。 w.Start(); 在该行之后。即使包括在内,节省的时间也会非常非常非常少。
    • 该行仅创建具有(我认为)8 个项目的基础数组的空列表。每次添加项目并且数组已满时,都会扩展和复制该列表。差异应该至少快两倍。
    • 这里有 100 万个整数被添加到列表中,一种方式没有初始大小,另一种方式有初始大小:dotnetfiddle.net/0DayU4 有区别,大约是 1.5 倍。但它的时间太短了,运行时间之间的自然变化往往会淹没它。以至于一些不提供大小的运行比提供它的运行快。提供尺寸更快,但可以忽略不计。
    • 明确地说,我认为这是个好建议。你说的是对的。但这不是“为什么这需要 10 秒?”的原因。
    • 哈哈不错的,好吧承认。我的预感是 25x 不仅仅是更有效地实现相同的算法。也许 Core 能够更多地了解代码并采取类似的捷径。如果只有框架变体比核心变体受到的影响更大,那么这可能指向那个方向。
    猜你喜欢
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 2018-07-10
    • 1970-01-01
    • 2022-11-02
    相关资源
    最近更新 更多