为什么这个Swift代码比Delphi实现慢?

时间:2014-12-29 18:14:20

标签: performance delphi swift

与其他语言相比,Apple吹捧了快速的性能。直到最近,当我开始在Swift中编写一些代码时,我从未怀疑过。

我在Swift中实现了xorshift算法,只是发现Swift版本比Delphi慢大约80倍。

Xorshift描述于http://en.wikipedia.org/wiki/Xorshift

SWIFT版本:

// xcrun -sdk macosx10.10 swiftc main.swift
import Foundation

func xor_shift(x0: UInt32, y0: UInt32, z0: UInt32, w0: UInt32) -> () -> UInt32 {
    var x = x0
    var y = y0
    var z = z0
    var w = w0

    func num() -> UInt32 {
        let t = x ^ (x << 11)
        x = y
        y = z
        z = w
        w = w ^ (w >> 19) ^ (t ^ (t >> 8))
        return w
    }

    return num
}


let loopcount = Int32.max
let xrand = xor_shift(2014, 12, 29, 2015)
let t0  = NSDate()

for _ in 0..<loopcount {
    xrand()
}

let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) millisecons, Loop count: \(loopcount)")

Delphi / Pascal版本:

// Command line compile:
// dcc64  xortest.dpr

{$APPTYPE CONSOLE}
program xortest;
uses sysutils;

type
  TRandSeed = record
    x,y,z,w: UInt32;
  end;

function xrand(var seed: TRandSeed): UInt32;
var
  t: UInt32;
begin
    t := seed.x xor (seed.x shl 11);
    seed.x := seed.y; seed.y := seed.z; seed.z := seed.w;
    seed.w := seed.w xor (seed.w shr 19) xor (t xor (t shr 8));
  result := seed.w
end;

var
  r: TRandSeed;
  t0, t1: TDateTime;
  s: string;
  i, loopcount: integer;
begin
  // Set the rand seed
  r.x := 2014;  r.y := 12;  r.z := 29;  r.w := 2015;

  loopcount := high(Int32);
  t0 := now;
  for i := 1 to loopcount do xrand(r);
  t1 := now;

  s := Format('[PASCAL] Time used: %d milliseconds, Loopcount = %d', [Trunc((t1-t0)*24*3600*1000), loopcount]);
  writeln(s);
end.

测试环境:

  1. OS X:iMac 27“retina 4 GHz Intel Core i7

  2. Windows 7在上述iMac上的VMWare融合中运行

  3. Swift版本输出:   [SWIFT]使用时间:412568毫秒,循环次数:2147483647

    Pascal版本输出:   [PASCAL]使用时间:5083毫秒,Loopcount = 2147483647

    Pascal版本运行速度比Swift版本快81倍,更不用说前者在虚拟机内运行了。 Apple是否在谈论Swift的快速性能,或者我的代码有什么问题吗?

2 个答案:

答案 0 :(得分:9)

编辑:哎呀,抱歉,我错误翻译了Delphi代码的一部分,所以不如常量计算好 - 但是封闭肯定是问题所以你应该重新对它进行比较,因为它会产生显着的差异

你的Swift代码不是你的Delphi代码的直接翻译,所以你不是在比较苹果和苹果。在Swift版本中,您正在调用一个函数,该函数返回一个捕获一些变量的闭包,然后调用该闭包。而在Delphi版本中,您只是调用一个带结构的函数。下面是Delphi代码的更直接的Swift转换。

闭包通常会成为编译器优化的障碍。删除这个障碍似乎对代码有很大的帮助,因为如果我在用-O编译后运行我的Swift等价物,它会在 0毫秒 5,341毫秒内计算2,147,483,647次xrand次运行,与可怕的古老笔记本电脑上的封闭版本相比,238,762毫秒。

为什么呢?因为没有优化的障碍,编译器有更多的自由度来尽可能快地重写代码。 可能甚至用一个常量值替换整个函数(它也可能检测到该值甚至没有被使用,因此根本不运行该函数,这就是为什么我添加了一个存储结果和结果的打印输出,以确保)。

import Foundation

struct TRandSeed {
    var x: UInt32
    var y: UInt32
    var z: UInt32
    var w: UInt32
}

func xrand(inout seed: TRandSeed) -> UInt32{
    var t = seed.x ^ (seed.x << 11)
    seed.x = seed.y
    seed.y = seed.z
    seed.z = seed.w
    seed.w = seed.w ^ (seed.w >> 19) ^ (t ^ (t >> 8))
    return seed.w
}

var r = TRandSeed(x: 2014, y: 12, z: 29, w: 2015)

let loopcount = Int32.max-1
let t0  = NSDate()

for _ in 0..<loopcount {
    xrand(&r)
}
let result = xrand(&r)

let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) millisecons to calculate \(result), Loop count: \(loopcount+1)")

答案 1 :(得分:0)

我稍微修改了Airspeed Velocity的代码:

import Foundation

struct TRandSeed {
    var x: UInt32
    var y: UInt32
    var z: UInt32
    var w: UInt32
}

func xrand(inout seed: TRandSeed) -> UInt32{
    let t = seed.x ^ (seed.x << 11)
    seed.x = seed.y
    seed.y = seed.z
    seed.z = seed.w
    seed.w = seed.w ^ (seed.w >> 19) ^ (t ^ (t >> 8))
    return seed.w
}

var r = TRandSeed(x: 2014, y: 12, z: 29, w: 2015)

let loopcount = Int32.max

let t0  = NSDate()
var total: UInt64 = 0

for _ in 0..<loopcount {
    let t = xrand(&r)
    total = total &+ UInt64(t)
}

let t1 = NSDate()
let ms = Int(t1.timeIntervalSinceDate(t0) * 1000)
println("[SWIFT] Time used: \(ms) milliseconds to calculate, Loop count: \(loopcount),  Total = \(total)")

我使用命令行编译它:xcrun -sdk macosx10.10 swiftc -O main.swift

新代码输出:[SWIFT]使用时间:2838毫秒计算,循环次数:2147483647,总计= 4611723097222874280

现在表现达到标准杆。 (由于Pascal版本在虚拟机内部运行,因此Swift二进制文件速度提高两倍是不公平的。)