编辑: 添加了 C# 代码的 unsafe 版本。谢谢你们的建议,unsafe C# 代码运行得更快,但只有大约 3%。

简短版本: 我用 C# 和 Objective-C 编写了一些基准代码,并在 iPad 3 上进行了测试。MonoTouch/C# 版本需要比 Objective-C 中的相同代码多 50%-150% 的时间来执行。这是我的问题: 我可以编写比我用于基准测试的代码(见下文)执行速度更快的 C# 代码,还是由某些固有的 MonoTouch/Obj-C 差异引起的?

长版: 我刚刚为计划中的多平台游戏编写了一个小原型(prototype)。将游戏核心从 Windows/.NET 移植到 iPad 3/MonoTouch 后,我注意到代码在 iPad 上运行速度慢了多少。游戏核心的某些关键部分在 iPad CPU 上的运行速度比在 Intel CPU 上慢约 10 倍(这似乎是正常的,因为 iPad 运行的是 ARM 处理器)。

然而,由于这是我们游戏的一个主要问题,我在 iPad 3 上进行了一个小型基准测试,一次是使用 MonoTouch ,然后是普通的 Objective-C 。基准测试做了很多简单的 float 添加和 float 数组查找。由于 MonoTouch 是 GC 的,我预计会看到有利于 Obj-C 的微小差异,但令我惊讶的是,MonoTouch 代码需要比 Obj-C 代码更多的时间来运行。准确地说:

  • Obj-C 代码需要 47'647 ms 在 DEBUG 模式下运行,27'162 ms 在 RELEASE 模式下运行。
  • MonoTouch 代码不使用 unsafe 指针需要 116'885 ms 在 DEBUG 模式下运行,40'002 ms 在 RELEASE 模式下运行。
  • MonoTouch 代码 带有 unsafe 指针 需要 90'372 ms 在 DEBUG 模式下运行,38'764 ms 在 RELEASE 模式下运行。

  • 当然,RELEASE 模式是我关心的。

    考虑到 MonoTouch 编译为与 Obj-C 相同的 native LLVM 代码,这种差异对我来说似乎有点高。

    这是我使用的 Obj-C 代码:
    int i, j;
    long time = GetTimeMs64();
    float * arr = (float *) malloc(10000 * sizeof(float)); //  10'000
    for (j = 0; j < 100000; j++) {                         // 100'000
        arr[0] = 0;
        arr[1] = 1;
        for (i = 2; i < 10000; i++) {                      //  10'000
            arr[i] = arr[i - 2] + arr[i - 1];
            if (arr[i] > 2000000000) {             // prevent arithm. overflow
                arr[i - 1] = 0;
                arr[i] = 1;
            }
        }
    }
    long time2 = GetTimeMs64() - time;
    
    GetTimeMs64() 使用 <sys/time.h>gettimeofday

    这是我的 C#/MonoTouch 代码,在 unsafe 版本中:
    var array = new float[10000];                          //  10'000
    var watch = System.Diagnostics.Stopwatch.StartNew();
    fixed (float* arr = array)
    {
        for (int j = 0; j < 100000; j++)                   // 100'000
        {
            *(arr + 0) = 0;
            *(arr + 1) = 1;
            for (int i = 2; i < 10000; i++)                //  10'000
            {
                *(arr + i) = *(arr + i - 2) + *(arr + i - 1);
                if (*(arr + i) > 2000000000)               // prevent arithm. overflow
                {
                    *(arr + i - 1) = 0;
                    *(arr + i) = 1;
                }
            }
        }
    }
    
    watch.Stop();
    

    编辑 2: 这是我们从 Xamarin 得到的答案:

    最佳答案

    就像 Marc 建议你应该使用 unsafe 代码一样,MonoTouch 支持这个 .NET 功能。

    这将删除 .NET 数组边界检查,这是 一个不错的、更安全的 .NET 功能,但会降低性能(因为每个数组访问 都必须检查 )。

    这将使您的代码看起来更像 Objective-C 代码(无论是在源代码中还是在 native 中),并且性能应该更接近。我仍然建议您仅在性能真正重要时才使用 unsafe 代码(并且在衡量 yield 是否值得之后)。

    关于c# - ObjC 与 MonoTouch 浮点和数组性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12428229/

    10-13 08:01