为什么在 while 循环中和在 while 循环中构造字典之间存在显著的性能差异?

Why there's significant performance difference between constructing dictionary in and out of a while loop?

提问人:謝康豪 提问时间:7/1/2022 最后编辑:謝康豪 更新时间:7/6/2022 访问量:131

问:

当我从大型 csv 文件中读取数据时,我面临着奇怪的性能差异。如果我在同一循环中读取数据并构造字典,如下面的代码片段所示,则该方法将花费大约 4.1 秒来完成该过程。

private void ReadFileWorkerRun(object sender, EventArgs e)
{
    List<Stock> lineTemp = new List<Stock>();
    List<Stock> allStock = new List<Stock>();
    List<List<Stock>> orderedAll = new List<List<Stock>>();
    Categories = new Dictionary<string, List<Stock>>() { { GlobalVariable.ALL, allStock } };
    DictionaryOrder = new List<(string, string)>();

    using (StreamReader lines = new StreamReader(FilePath))
    {
        string line = lines.ReadLine();

        // Add each stock to dictionary
        while ((line = lines.ReadLine()) != null)
        {
            Stock temp = new Stock(line);

            // This is the upper boundary of the code that will move outside of the using statement
            if (!Categories.TryGetValue(temp.StockID, out List<Stock> targetList))
            {
                targetList = new List<Stock>();
                orderedAll.Add(targetList);
                Categories.Add(temp.StockID, targetList);
                DictionaryOrder.Add((temp.StockID, temp.StockName));
            }
            targetList.Add(temp);
            // This is the lower boundary of the code that will move outside of the using statement
        }
    }
    /*
    The code between the boundry is moved here
    */
    foreach (List<Stock> stockList in orderedAll)
    {
        allStock.AddRange(stockList);
    }
}
public class Stock
    {
        public string StockDate { get; set; }

        public string StockID { get; set; }

        public string StockName { get; set; }

        public string SecBrokerID { get; set; }

        public string SecBrokerName { get; set; }

        public decimal Price { get; set; }

        public long BuyQty{ get; set; }

        public long SellQty { get; set; }

        public Stock(string s)
        {
            string[] data = s.Split(',');
            StockDate = data[0];
            StockID = data[1];
            StockName = data[2];
            SecBrokerID = data[3];
            SecBrokerName = data[4];
            Price = decimal.Parse(data[5]);
            BuyQty = long.Parse(data[6]);
            SellQty = long.Parse(data[7]);
        }
    }

但是,当我将构造字典的代码部分移出 while 循环并将其放入 foreach 循环中时,该方法所花费的时间将变为 3.4 秒。using 语句中的代码分为以下代码:

using (StreamReader lines = new StreamReader(FilePath))
{
    string line = lines.ReadLine();

    while ((line = lines.ReadLine()) != null)
    {
            lineTemp.Add(new Stock(line));
    }
}

// Add each stock to dictionary
foreach (Stock temp in lineTemp)
{
    if (!Categories.TryGetValue(temp.StockID, out List<Stock> targetList))
    {
        targetList = new List<Stock>();
        orderedAll.Add(targetList);
        Categories.Add(temp.StockID, targetList);
        DictionaryOrder.Add((temp.StockID, temp.StockName));
    }
    targetList.Add(temp);
}

两个版本之间的唯一区别是我在第二部分中列出的代码,无论我运行多少次,时间间隔始终是一致的,那么为什么具有相同逻辑和数据结构的代码的行为如此不同呢?

C# 性能 字典 while-loop foreach

评论

2赞 mksmanjit 7/1/2022
您是否尝试过多次运行该程序以查看您是否始终如一地获得差异,当您从文件中读取时,可能需要一段时间,下次会很慢,尝试运行两个程序 4-5 次以查看您获得的平均差异。
2赞 Karl Knechtel 7/1/2022
欢迎来到 Stack Overflow。“我是 stackoverflow 的新手,如果我忽略了一些提出正确问题的技巧,请随时注意到我。”在我看来,写这个实际上是你真正做错了的事情——这不是一个讨论论坛,所以问题应该包含问题本身(以及理解它所需的相关代码等)。没有必要为自己找借口;无论如何,我们都应该保持礼貌,我们将帮助您解决我们所能解决的问题,并告诉您需要输入的内容。
0赞 Karl Knechtel 7/1/2022
但是,如果您真的想让问题变得最好,请阅读最小的可重现示例,并考虑是否可以在演示问题的同时简化代码。
0赞 謝康豪 7/1/2022
是的,我愿意。我跑了好几次,结果总是一致的。
1赞 JonasH 7/1/2022
我建议根据内存流而不是实际文件进行测量。由于缓存等原因,测量涉及 IO 的任何内容都可能非常复杂。因此,我建议先将数据复制到内存流中。

答: 暂无答案