【问题标题】:Why are for loops in D so much slower than for loops in C#?为什么 D 中的 for 循环比 C# 中的 for 循环慢得多?
【发布时间】:2013-12-29 04:25:40
【问题描述】:

我有以下两段 C# 和 D 代码,目的是在一个简单的循环中比较速度。

D:

import std.stdio;
import std.datetime;

void main() {
    StopWatch timer;
    long summer = 0;
    timer.start();
    for (long i = 0; i < 10000000000; i++){
        summer++;
    }
    timer.stop();
    long interval_t = timer.peek().msecs;
    writeln(interval_t);
}

输出:大约 30 秒

C#:

using System;
using System.Diagnostics;

class Program{
    static void Main(){
        Stopwatch timer = new Stopwatch();
        timer.Start();
        long summer = 0;
        for(long i = 0; i < 10000000000; i++){
            summer++;
        }
        timer.Stop();
        Console.WriteLine(timer.ElapsedMilliseconds);
    }
}

输出:大约 8 秒

为什么 C# 代码这么快?

【问题讨论】:

  • @MarcinJuraszek 另一个简单的问题。您阅读问题的标题了吗?
  • 他想问的本质是:“你在运行D编译器的时候启用了优化吗?”
  • 令人惊讶的是,您在循环之后没有对 Summer 变量执行任何操作,但 C# 却需要 8 秒,不确定为什么它不能消除整个操作。
  • 如果您还没有启用优化,请尝试在 DMD 中启用优化。 -O -inline -release -noboundscheck.
  • 在 D 编译器上启用优化也会将结果更改为大约 7 秒。感谢您的回答,我没想到差异如此之大。

标签: c# performance benchmarking d


【解决方案1】:

这不仅仅是说:“你没有打开优化器。”

至少在猜测中,您(最初)在任何一种情况下都没有打开优化器。尽管如此,开启了没有优化的C#版本的运行速度几乎与优化的D版本一样快。为什么会这样?

答案源于编译模型的不同。 D 进行静态编译,因此源代码被转换为包含机器代码的可执行文件,然后执行。唯一发生的优化是在静态编译期间所做的任何事情。

相比之下,C# 将源代码转换为 MSIL,一种中间语言(即基本上是字节码)。然后通过内置在 CLR(公共语言运行时——微软的 MSIL 虚拟机)中的 JIT 编译器将其翻译成机器语言。您可以在运行 C# 编译器时指定优化。这仅在进行从源代码到字节代码的初始编译时控制优化。当您运行代码时,JIT 编译器会做它的事情——无论您是否在从源代码到字节代码的初始转换中指定优化,它都会做它的优化。这就是为什么当您没有指定任何一种优化时,使用 C# 比使用 D 获得更快的结果。

我觉得有必要补充一下,您得到的 both 结果(D 和 C# 分别为 7 秒和 8 秒)真的很糟糕。一个体面的优化器应该认识到最终输出根本不依赖于循环,并且基于此它应该完全消除循环。只是为了比较,我做了(大约)我能做的最直接的 C++ 翻译:

#include <iostream>
#include <time.h>

int main() {
    long summer = 0;
    auto start = clock();
    for (long i = 0; i < 10000000000; i++)
        summer++;
    std::cout << double(clock() - start) / CLOCKS_PER_SEC;
}

使用cl /O2b2 /GL 使用 VC++ 编译,这始终显示时间为 0。

【讨论】:

  • 感谢您抽出宝贵时间回答如此深入的问题。 A 级答案。
  • 有人提交了一个错误。这是优化器的旧帽子,对于 D 中的所有 CTFE 内容,它应该是相当微不足道的:只需跟踪确定性和 CTFE(几乎)任何输入如此标记的内容。
  • LDC 也有 0 秒。这只是证实了广泛传播的观点,即如果优化真的很重要,则不应使用 DMD。
【解决方案2】:

我认为你的问题应该标题为:

为什么在此处插入你的D编译器>编译的for循环比在此处插入你的C#编译器/运行时>编译的for循环慢得多?> p>

不同实现的性能可能会有很大差异,这不是语言本身的特征。您可能正在使用 DMD,参考 D 编译器,它以使用高度优化的后端而闻名。为获得最佳性能,请尝试 GDC 或 LDC 编译器。

您还应该发布您使用的编译选项(优化可能仅使用一个编译器启用)。

有关更多信息,请参阅此问题: How fast is D compared to C++?

【讨论】:

  • 一个好的、最先进的编译器/优化器应该能够将整个循环减少到summer += 10000000000; 事实上,这并没有演变为Stopwatch 的基准,这表明它的某些内容自我。
【解决方案3】:

一些答案​​表明优化器会优化整个循环。

大多数情况下,他们明确这样做,因为他们期望程序员将循环编码为计时循环。

这种技术通常用于硬件驱动程序中等待的时间段比设置定时器和处理定时器中断所用的时间短。

这就是在 linux 启动时进行“bogomips”计算的原因...校准这个特定 CPU/编译器每秒可以执行多少次紧密循环的迭代。

【讨论】:

    猜你喜欢
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2022-01-04
    • 2014-01-21
    • 2017-11-09
    • 1970-01-01
    • 2014-07-21
    相关资源
    最近更新 更多