【问题标题】:Cost of common operations for C#?C# 的常见操作的成本?
【发布时间】:2010-10-26 17:24:22
【问题描述】:

Code Complete 2(第 601 和 602 页)中有一个“通用操作成本”表。

基准操作整数赋值被赋予值 1,然后列出 Java 和 C++ 的常见操作的相对时间。例如:

                                  C++        Java
Integer assignment                1             1
Integer division                  5             1.5
Floating point square root       15             4 

问题是有人得到了 C# 的这些数据吗?我知道这些不会帮助我专门解决任何问题,我只是好奇。

【问题讨论】:

  • (所有 .NET 语言都一样)
  • 看起来像过早优化的过早优化......这些操作将在汇编代码中执行,但基准测试将在实际运行时运行,恕我直言,它将测试基准测试很慢,而不是机器指令。跨度>

标签: c# performance optimization operators


【解决方案1】:

我实现了书中的一些测试。我电脑上的一些原始数据:

测试运行 #1:

TestIntegerAssignment 00:00:00.6680000
TestCallRoutineWithNoParameters 00:00:00.9780000
TestCallRoutineWithOneParameter 00:00:00.6580000
TestCallRoutineWithTwoParameters 00:00:00.9650000
TestIntegerAddition 00:00:00.6410000
测试整数减法 00:00:00.9630000
测试整数乘法 00:00:00.6490000
TestIntegerDivision 00:00:00.9720000
TestFloatingPointDivision 00:00:00.6500000
TestFloatingPointSquareRoot 00:00:00.9790000
TestFloatingPointSine 00:00:00.6410000
TestFloatingPointLogarithm 00:00:41.1410000
TestFloatingPointExp 00:00:34.6310000

测试运行 #2:

TestIntegerAssignment 00:00:00.6750000
TestCallRoutineWithNoParameters 00:00:00.9720000
TestCallRoutineWithOneParameter 00:00:00.6490000
TestCallRoutineWithTwoParameters 00:00:00.9750000
TestIntegerAddition 00:00:00.6730000
测试整数减法 00:00:01.0300000
测试整数乘法 00:00:00.7000000
TestIntegerDivision 00:00:01.1120000
TestFloatingPointDivision 00:00:00.6630000
TestFloatingPointSquareRoot 00:00:00.9860000
TestFloatingPointSine 00:00:00.6530000
TestFloatingPointLogarithm 00:00:39.1150000
TestFloatingPointExp 00:00:33.8730000

测试运行#3:

TestIntegerAssignment 00:00:00.6590000
TestCallRoutineWithNoParameters 00:00:00.9700000
TestCallRoutineWithOneParameter 00:00:00.6680000
TestCallRoutineWithTwoParameters 00:00:00.9900000
TestIntegerAddition 00:00:00.6720000
测试整数减法 00:00:00.9770000
测试整数乘法 00:00:00.6580000
TestIntegerDivision 00:00:00.9930000
TestFloatingPointDivision 00:00:00.6740000
TestFloatingPointSquareRoot 00:00:01.0120000
TestFloatingPointSine 00:00:00.6700000
TestFloatingPointLogarithm 00:00:39.1020000
TestFloatingPointExp 00:00:35.3560000

(每个基准测试 10 亿次测试,使用 Optimize 编译,AMD Athlon X2 3.0ghz,使用 Jon Skeet 的微基准测试框架,http://www.yoda.arachsys.com/csharp/benchmark.html

来源:

class TestBenchmark  
{  
[Benchmark]  
public static void TestIntegerAssignment()
{
int i = 1;
int j = 2;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j;
    }
}

[Benchmark]
public static void TestCallRoutineWithNoParameters()
{
    for (int x = 0; x < 1000000000; x++)
    {
        TestStaticRoutine();
    }
}

[Benchmark]
public static void TestCallRoutineWithOneParameter()
{
    for (int x = 0; x < 1000000000; x++)
    {
        TestStaticRoutine2(5);
    }
}

[Benchmark]
public static void TestCallRoutineWithTwoParameters()
{
    for (int x = 0; x < 1000000000; x++)
    {
        TestStaticRoutine3(5,7);
    }
}

[Benchmark]
public static void TestIntegerAddition()
{
    int i = 1;
    int j = 2;
    int k = 3;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j + k;
    }
}

[Benchmark]
public static void TestIntegerSubtraction()
{
    int i = 1;
    int j = 6;
    int k = 3;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j - k;
    }
}

[Benchmark]
public static void TestIntegerMultiplication()
{
    int i = 1;
    int j = 2;
    int k = 3;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j * k;
    }
}


[Benchmark]
public static void TestIntegerDivision()
{
    int i = 1;
    int j = 6;
    int k = 3;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j/k;
    }
}

[Benchmark]
public static void TestFloatingPointDivision()
{
    float i = 1;
    float j = 6;
    float k = 3;

    for (int x = 0; x < 1000000000; x++)
    {
        i = j / k;
    }
}

[Benchmark]
public static void TestFloatingPointSquareRoot()
{
    double x = 1;
    float y = 6;

    for (int x2 = 0; x2 < 1000000000; x2++)
    {
        x = Math.Sqrt(6);
    }
}

[Benchmark]
public static void TestFloatingPointSine()
{
    double x = 1;
    float y = 6;

    for (int x2 = 0; x2 < 1000000000; x2++)
    {
        x = Math.Sin(y);
    }
}

[Benchmark]
public static void TestFloatingPointLogarithm()
{
    double x = 1;
    float y = 6;

    for (int x2 = 0; x2 < 1000000000; x2++)
    {
        x = Math.Log(y);
    }
}

[Benchmark]
public static void TestFloatingPointExp()
{
    double x = 1;
    float y = 6;

    for (int x2 = 0; x2 < 1000000000; x2++)
    {
        x = Math.Exp(6);
    }
}

private static void TestStaticRoutine() {

}

private static void TestStaticRoutine2(int i)
{

}

private static void TestStaticRoutine3(int i, int j)
{

}

private static class TestStaticClass
{

}

【讨论】:

  • 我会对结果做一些事情(比如 Console.WriteLine 它),只是为了绝对确保它不会被优化掉。可能不会,但是...
  • 你不觉得每一个结果都是~0.33、~0.66或~0.99有点奇怪吗?尤其是当使用 0,1,2 参数的调用得到 0.9,0.6,0.9 时,我会开始怀疑测试方法。也可以内联私有静态函数。恕我直言,这是一个非常糟糕的测试。
  • 这个基准测试是假的。由于循环中使用了加法,每个测试也有做 1000000000 次加法的开销。为了正确地进行此测试,您可能还需要弄清楚将 1000000000 个数字相加花费了多少时间。
【解决方案2】:

直接来自源代码,Know what things cost

IIRC Rico Mariani 有你要求的 on his blog 的相关措施,但我再也找不到它了(我知道它在两个“开发”书签之一中......)

【讨论】:

    【解决方案3】:

    这是一个合理的问题,但我看到的几乎所有性能问题,尤其是在 Java 和 C# 中,都归结为:

    • 抽象层太多,并且
    • 依赖基于事件的通知样式编码。

    与基本操作几乎没有关系。

    抽象的问题是在工作量变得繁重之前都可以。每一层通常都会造成很小的性能损失,并且这些损失会以复合方式累积。那时,您开始需要解决方法。 (我认为 StringBuilder 就是这种解决方法的一个例子。)

    基于事件的通知式编码(与通过周期性过程保持一致的更简单的数据结构相反)的问题在于,看似简单的操作(例如将属性设置为值)可能会导致连锁反应整个数据结构中的操作所产生的影响远远超出人们的预期。

    【讨论】:

      猜你喜欢
      • 2011-01-20
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      相关资源
      最近更新 更多