关于macos:为什么Swift在这个图像处理测试中比C慢100倍?

Why Swift is 100 times slower than C in this image processing test?

本问题已经有最佳答案,请猛点这里访问。

像许多其他开发者一样,我对苹果的新的Swift语言感到非常兴奋。苹果声称它的速度比目标C快,可以用来编写操作系统。据我目前所学,它是一种静态类型的语言,能够精确地控制精确的数据类型(比如整数长度)。所以,它看起来确实有很好的潜在处理性能关键任务,比如图像处理,对吧?

这就是我在做快速测试之前的想法。结果真让我吃惊。

下面是C中的一个简单代码段:

测试:C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdint.h>
#include <string.h>

uint8_t pixels[640*480];
uint8_t alpha[640*480];
uint8_t blended[640*480];

void blend(uint8_t* px, uint8_t* al, uint8_t* result, int size)
{
    for(int i=0; i<size; i++) {
        result[i] = (uint8_t)(((uint16_t)px[i]) *al[i] /255);
    }
}

int main(void)
{
    memset(pixels, 128, 640*480);
    memset(alpha, 128, 640*480);
    memset(blended, 255, 640*480);

    // Test 10 frames
    for(int i=0; i<10; i++) {
        blend(pixels, alpha, blended, 640*480);
    }

    return 0;
}

我用以下命令在我的MacBook Air 2011上编译了它:

1
clang -O3 test.c -o test

10帧处理时间约为0.01s,换言之,C码1 ms处理一帧:

1
2
3
4
$ time ./test
real    0m0.010s
user    0m0.006s
sys     0m0.003s

然后我有一个快速版本的相同代码:

斯威夫特:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let pixels = UInt8[](count: 640*480, repeatedValue: 128)
let alpha = UInt8[](count: 640*480, repeatedValue: 128)
let blended = UInt8[](count: 640*480, repeatedValue: 255)

func blend(px: UInt8[], al: UInt8[], result: UInt8[], size: Int)
{
    for(var i=0; i<size; i++) {
        var b = (UInt16)(px[i]) * (UInt16)(al[i])
        result[i] = (UInt8)(b/255)
    }
}

for i in 0..10 {
    blend(pixels, alpha, blended, 640*480)
}

生成命令行是:

1
xcrun swift -O3 test.swift -o test

在这里,我使用相同的O3级优化标志,希望能够公平地进行比较。但是,产生的速度慢了100倍:

1
2
3
4
5
$ time ./test

real    0m1.172s
user    0m1.146s
sys     0m0.006s

换言之,处理一帧需要大约120ms的时间,而处理一帧只需要1 ms的时间。

怎么搞的?

更新:我正在使用clang:

1
2
3
4
5
$ gcc -v
Configured with: --prefix=/Applications/Xcode6-Beta.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.34.4) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix

更新:不同运行迭代的更多结果:

这里是不同数量"帧"的结果,即将主for循环数从10更改为其他数字。注意,现在我的C代码时间更快了(缓存热?)虽然时间变化不大:

1
2
3
4
5
             C Time (s)      Swift Time (s)
  1 frame:     0.005            0.130
 10 frames(*): 0.006            1.196
 20 frames:    0.008            2.397
100 frames:    0.024           11.668

更新:`-ofast`帮助

有了@mweathers建议的-Ofast,快速速度达到了合理的范围。

在我的笔记本电脑上,带-Ofast的Swift版本10帧0.013秒,100帧0.048秒,接近C性能的一半。


建筑与:

xcrun swift -Ofast test.swift -o test

我得到的时间是:

1
2
3
real    0m0.052s
user    0m0.009s
sys 0m0.005s


让我们集中讨论这个问题的答案,它从一个"为什么"开始:因为您没有启用优化,而Swift严重依赖于编译器优化。

也就是说,在C中进行图像处理是非常愚蠢的。这就是你拥有CGIMAGE和朋友的目的。