【问题标题】:List<string> declaration speed differences in debug mode调试模式下的 List<string> 声明速度差异
【发布时间】:2019-06-26 02:51:38
【问题描述】:

我使用 System.Diagnostics.StopWatch 类为 C# 创建了一个小型基准测试控制台应用程序,以观察 3 个方法需要多长时间:

我如何运行基准测试:

public void Run()
{
    Stopwatch sw = new Stopwatch();

    sw.Start();
    InitDirectly();
    sw.Stop();
    Console.WriteLine($"InitDirectly: {sw.Elapsed.TotalMilliseconds}ms");

    sw.Reset();

    sw.Start();
    InitWithAdd();
    sw.Stop();
    Console.WriteLine($"InitWithAdd: {sw.Elapsed.TotalMilliseconds}ms");

    sw.Reset();

    sw.Start();
    InitWithForLoop();
    sw.Stop();
    Console.WriteLine($"InitWithForLoop: {sw.Elapsed.TotalMilliseconds}ms");
}

方法一:

private void InitListDirectly()
{
    var list = new List<string>() {
        "string",
        "string",
        "string",
        //... up to a 100th entry
    };
}

方法二:

private void InitListViaAdd()
{
    var list = new List<string>();
    list.Add("string");
    list.Add("string");
    list.Add("string");
    //... up to a 100th entry
}

方法三:

private void InitListViaForLoop() {
    var list = new List<string>();
    for (int i = 0; i < 100; i++) {
        list.Add("string");
    }
}

现在在方法 1 之前启动秒表,然后停止。 方法 2 相同。

  1. 方法 1 耗时约 0.800 毫秒
  2. 方法 2 耗时约 1.000 毫秒
  3. 方法 3 耗时约 0.120 毫秒

现在我很惊讶,for 循环(方法 3)的速度如此之快。我希望方法 1 最快,因为其他两种方法必须调用“Add(string)”,而第三种方法必须创建一个 for 循环。

为什么方法 3 这么快?这是由于一些编译器魔法吗?它是否意识到 for 循环中的语句对于它的所有迭代都是相同的?

编辑:我在调试模式下运行。

【问题讨论】:

  • 顺便说一下,Method1 和 Method2 在内部是相同的,列表初始化器的语法只是做大量list.Add 调用的糖。
  • 你应该包括测试,因为我认为你测量不正确
  • 我对你的结果持怀疑态度。你确定你的基准测试正确吗?
  • 您是在发布模式还是调试模式下运行此代码?我怀疑如果您使用发布模式,这两种方法将花费相同的时间。
  • 我用bechmarkDotNet 对此进行了基准测试,结果是:[922.054ns]、[921.826ns]、[946.982ns] 所以大致相等。您必须在发行版中编译,在没有调试器的情况下(从控制台)执行它并使用预热并取平均值。

标签: c# list initialization iteration benchmarking


【解决方案1】:

这不是您问题的答案,但如果您使用BenchmarkDotNet 进行测试,您的问题可能会有所不同。

【讨论】:

    【解决方案2】:

    将 100 个字符串添加到 List&lt;&gt; 需要整整一毫秒?这就像 2 到 4 百万个时钟周期!这太疯狂了,而且比调试模式解释实际运行代码的时间要长得多。

    由于您只调用每个函数一次,也许这包括 JIT 编译函数的时间?

    即使在调试模式下,带有循环的短函数也可以比大型函数更容易地 JIT 转换为机器代码,因为 JIT 编译器要处理的字节码要少得多。

    【讨论】:

    • 啊哈!这是一个很好的观点,我将研究 JIT 编译的想法。是的,第一次通话花费了将近一毫秒,随后的通话花费了我认为的 0.03 毫秒,所以更少
    猜你喜欢
    • 2011-05-22
    • 2015-05-25
    • 2014-12-01
    • 2018-03-18
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多