Swift Beta性能:排序数组

Swift Beta performance: sorting arrays

我在Swift测试版中实现了一个算法,注意到性能非常差。在深入挖掘之后,我意识到其中一个瓶颈就是排序数组。相关部分如下:

1
2
3
4
5
6
7
8
let n = 1000000
var x =  [Int](repeating: 0, count: n)
for i in 0..<n {
    x[i] = random()
}
// start clock here
let y = sort(x)
// stop clock here

在C++中,类似的操作在我的计算机上需要0.06s。

在python中,它需要0.6秒(不需要技巧,只需要y=sorted(x)代表整数列表)。

在swift中,如果我使用以下命令编译它,则需要6s:

1
xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`

如果我用以下命令编译它,它需要多达88秒的时间:

1
xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`

xcode中"release"与"debug"构建的时间安排相似。

这里怎么了?与C++相比,我可以理解一些性能损失,但与纯Python相比,它并没有减慢10倍。

编辑:天气注意到,将EDCOX1的0个变量改为EDCOX1(1),使得这个代码运行的速度几乎和C++版本一样快!然而,-Ofast改变了语言的语义很多——在我的测试中,它禁用了对整数溢出和数组索引溢出的检查。例如,使用-Ofast时,以下swift代码会安静运行,不会崩溃(并打印出一些垃圾):

1
2
3
4
let n = 10000000
print(n*n*n*n*n)
let x =  [Int](repeating: 10, count: n)
print(x[n])

因此,我们不希望以东十一〔一〕号;斯威夫特的关键是我们有安全网。当然,安全网对性能有一定的影响,但不能使程序慢100倍。请记住,Java已经检查数组的界限,并且在典型的情况下,增长速度小于2。在clang和gcc中,我们得到了用于检查(有符号)整数溢出的-ftrapv,而且速度也不慢。

因此,问题是:我们如何在不丢失安全网的情况下,迅速获得合理的性能?

编辑2:我做了更多的基准测试,沿着

1
2
3
for i in 0..<n {
    x[i] = x[i] ^ 12345678
}

(这里有XOR操作,这样我就可以更容易地在汇编代码中找到相关的循环。我试图选择一个容易发现但又"无害"的操作,因为它不需要任何与整数溢出相关的检查。)

同样,-O3-Ofast在性能上有很大的差异。所以我看了一下汇编代码:

  • 有了-Ofast,我得到了我所期望的。相关部分是一个包含5个机器语言指令的循环。

  • 有了-O3,我得到了超乎想象的东西。内部循环跨越88行汇编代码。我没有试图理解所有这些,但最可疑的部分是13次调用"callq-swift-retain"和另外13次调用"callq-swift-release"。也就是说,26个子例程在内部循环中调用!

编辑3:在评论中,Ferroccio要求基准是公平的,因为它们不依赖内置函数(例如sort)。我认为以下程序是一个相当好的例子:

1
2
3
4
5
6
7
let n = 10000
var x = [Int](repeating: 1, count: n)
for i in 0..<n {
    for j in 0..<n {
        x[i] = x[j]
    }
}

没有算术,所以我们不需要担心整数溢出。我们唯一要做的就是大量的数组引用。结果是,与-ofast相比,swift-o3损失了近500倍:

  • C++O3:0.05 s
  • C++O0:0.4 S
  • 爪哇:0.2秒
  • pypy的python:0.5秒
  • Python:12秒
  • 快速-OFAST:0.05秒
  • SWOT-O3:23秒
  • 斯威夫特-O0:443 S

(如果您担心编译器可能会完全优化无意义循环,可以将其更改为例如x[i] ^= x[j],并添加输出x[0]的print语句。这不会改变任何事情;时间安排将非常相似。)

是的,这里的python实现是一个愚蠢的纯python实现,有一个int列表,嵌套for循环。它应该比未经优化的swift慢得多。快速和数组索引似乎严重破坏了某些功能。

编辑4:这些问题(以及其他一些性能问题)似乎已经在Xcode6测试版5中得到了解决。

对于排序,我现在有以下时间安排:

  • clang++-o3:0.06秒
  • Swiftc-OFast:0.1秒
  • 开关柜-O:0.1s
  • SWIFTC:4秒

对于嵌套循环:

  • clang++-o3:0.06秒
  • Swiftc-OFast:0.3秒
  • 开关柜-O:0.4s
  • SWIFTC:540秒

似乎没有理由再使用不安全的-Ofast(a.k.a.-Ounchecked;普通的-O产生同样好的代码。


TL;DrSwift1.0现在使用默认版本优化级别的基准测试速度与C一样快。

这里有一个在swift beta中的就地快速排序:

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
func quicksort_swift(inout a:CInt[], start:Int, end:Int) {
    if (end - start < 2){
        return
    }
    var p = a[start + (end - start)/2]
    var l = start
    var r = end - 1
    while (l <= r){
        if (a[l] < p){
            l += 1
            continue
        }
        if (a[r] > p){
            r -= 1
            continue
        }
        var t = a[l]
        a[l] = a[r]
        a[r] = t
        l += 1
        r -= 1
    }
    quicksort_swift(&a, start, r + 1)
    quicksort_swift(&a, r + 1, end)
}

C中相同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void quicksort_c(int *a, int n) {
    if (n < 2)
        return;
    int p = a[n / 2];
    int *l = a;
    int *r = a + n - 1;
    while (l <= r) {
        if (*l < p) {
            l++;
            continue;
        }
        if (*r > p) {
            r--;
            continue;
        }
        int t = *l;
        *l++ = *r;
        *r-- = t;
    }
    quicksort_c(a, r - a + 1);
    quicksort_c(l, a + n - l);
}

两种工作:

1
2
3
4
5
6
7
8
var a_swift:CInt[] = [0,5,2,8,1234,-1,2]
var a_c:CInt[] = [0,5,2,8,1234,-1,2]

quicksort_swift(&a_swift, 0, a_swift.count)
quicksort_c(&a_c, CInt(a_c.count))

// [-1, 0, 2, 2, 5, 8, 1234]
// [-1, 0, 2, 2, 5, 8, 1234]

这两个都是在编写的同一个程序中调用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var x_swift = CInt[](count: n, repeatedValue: 0)
var x_c = CInt[](count: n, repeatedValue: 0)
for var i = 0; i < n; ++i {
    x_swift[i] = CInt(random())
    x_c[i] = CInt(random())
}

let swift_start:UInt64 = mach_absolute_time();
quicksort_swift(&x_swift, 0, x_swift.count)
let swift_stop:UInt64 = mach_absolute_time();

let c_start:UInt64 = mach_absolute_time();
quicksort_c(&x_c, CInt(x_c.count))
let c_stop:UInt64 = mach_absolute_time();

这将绝对时间转换为秒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MSEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MSEC;

mach_timebase_info_data_t timebase_info;

uint64_t abs_to_nanos(uint64_t abs) {
    if ( timebase_info.denom == 0 ) {
        (void)mach_timebase_info(&timebase_info);
    }
    return abs * timebase_info.numer  / timebase_info.denom;
}

double abs_to_seconds(uint64_t abs) {
    return abs_to_nanos(abs) / (double)NANOS_PER_SEC;
}

以下是编译器优化级别的摘要:

1
2
3
[-Onone] no optimizations, the default for debug.
[-O]     perform optimizations, the default for release.
[-Ofast] perform optimizations and disable runtime overflow checks and runtime type checks.

以秒为单位的时间,其中n=10_的时间为[-onone]。

1
2
Swift:            0.895296452
C:                0.001223848

以下是Swift的内置排序(),用于n=10_:

1
Swift_builtin:    0.77865783

这里是用于n=10_000的[-o]

1
2
3
Swift:            0.045478346
C:                0.000784666
Swift_builtin:    0.032513488

如你所见,斯威夫特的表现提高了20倍。

根据mWeathers的回答,设置[-ofast]会产生真正的差异,导致n=10_000的这些时间:

1
2
3
Swift:            0.000706745
C:                0.000742374
Swift_builtin:    0.000603576

n=1_时:

1
2
3
Swift:            0.107111846
C:                0.114957179
Swift_sort:       0.092688548

比较而言,n=1_时,这与[-onone]是一致的:

1
2
3
Swift:            142.659763258
C:                0.162065333
Swift_sort:       114.095478272

所以在这个基准测试中,在开发的这个阶段,没有优化的Swift比C慢了近1000倍。另一方面,当两个编译器都设置为[-ofast]时,如果不是略好于c,那么swift实际上至少也执行了相同的操作。

有人指出,[-ofast]会改变语言的语义,使其具有潜在的不安全性。这就是苹果在Xcode5.0发行说明中所说的:

A new optimization level -Ofast, available in LLVM, enables aggressive optimizations. -Ofast relaxes some conservative restrictions, mostly for floating-point operations, that are safe for most code. It can yield significant high-performance wins from the compiler.

他们几乎都鼓吹它。不管这是明智还是不明智,我都不能说,但是从我所知道的来看,在一个版本中使用[-ofast]似乎足够合理,如果您不执行高精度浮点运算,并且您确信在您的程序中不可能有整数或数组溢出。如果您确实需要高性能和溢出检查/精确算术,那么现在就选择另一种语言。

贝塔3更新:

n=10_,带[-o]:

1
2
3
Swift:            0.019697268
C:                0.000718064
Swift_sort:       0.002094721

一般来说,斯威夫特的速度有点快,看起来斯威夫特的内置类型已经发生了很大的变化。

最后更新:

[OnOne ]:

1
2
Swift:   0.678056695
C:       0.000973914

[-O]:

1
2
Swift:   0.001158492
C:       0.001192406

[-NoChest]:

1
2
Swift:   0.000827764
C:       0.001078914


TL;Dr:是的,目前唯一快速的语言实现速度很慢。如果您需要快速的、数字的(和其他类型的代码,大概)代码,只需使用另一种代码。将来,你应该重新评估你的选择。不过,对于大多数在更高级别编写的应用程序代码来说,这可能已经足够好了。

从我在SIL和llvm ir中看到的情况来看,它们似乎需要一系列的优化来删除保留和发布,这些优化可能在clang(对于objective-c)中实现,但它们还没有移植它们。这就是我要遵循的理论(目前……我仍然需要确认clang对此做了些什么),因为在这个问题的最后一个测试用例上运行的分析器会产生这个"漂亮"的结果:

Time profiling on -O3Time profiling on -Ofast

正如许多人所说,-Ofast是完全不安全的,它改变了语言语义。对我来说,这是在"如果你要用它,就用另一种语言"的阶段。如果改变的话,我稍后会重新评估这个选择。

-O3给我们带来了一堆swift_retainswift_release的电话,老实说,他们看起来不应该出现在这个例子中。由于优化器知道关于数组的大部分信息,并且知道它(至少)有一个对数组的强引用,所以它应该已经将它们(大部分)删除了。

当它甚至不调用可能释放对象的函数时,它不应该发出更多的保留。我不认为数组构造函数可以返回一个比要求的小的数组,这意味着许多发出的检查都是无用的。它还知道整数永远不会超过10000,因此可以优化溢出检查(不是因为-Ofast的怪异,而是因为语言的语义(没有任何其他变化,var也不能访问它,加起来最多10000对于Int类型是安全的)。

不过,编译器可能无法取消对数组或数组元素的装箱,因为它们将被传递给sort(),后者是一个外部函数,必须获得它期望的参数。这将使我们不得不间接地使用Int值,这将使其速度变慢。如果编译器可以使用sort()泛型函数(而不是以多方法的方式),并且该函数是内联的,则可能会发生变化。

这是一种非常新的(公开的)语言,我认为它正在经历很多变化,因为有人(严重地)参与了快速语言的请求反馈,他们都说语言还没有完成,将要改变。

使用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Cocoa

let swift_start = NSDate.timeIntervalSinceReferenceDate();
let n: Int = 10000
let x = Int[](count: n, repeatedValue: 1)
for i in 0..n {
    for j in 0..n {
        let tmp: Int = x[j]
        x[i] = tmp
    }
}
let y: Int[] = sort(x)
let swift_stop = NSDate.timeIntervalSinceReferenceDate();

println("\(swift_stop - swift_start)s")

P.S:我不是Objective-C的专家,也不是来自Cocoa、Objective-C或Swift Runtimes的所有设备。我可能也在假设一些我没有写的东西。


为了好玩,我决定看看这个,下面是我得到的时间安排:

1
2
Swift 4.0.2           :   0.83s (0.74s with `-Ounchecked`)
C++ (Apple LLVM 8.0.0):   0.74s

迅捷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Swift 4.0 code
import Foundation

func doTest() -> Void {
    let arraySize = 10000000
    var randomNumbers = [UInt32]()

    for _ in 0..<arraySize {
        randomNumbers.append(arc4random_uniform(UInt32(arraySize)))
    }

    let start = Date()
    randomNumbers.sort()
    let end = Date()

    print(randomNumbers[0])
    print("Elapsed time: \(end.timeIntervalSince(start))")
}

doTest()

结果:

斯威夫特1.1

1
2
3
4
5
6
7
xcrun swiftc --version
Swift version 1.1 (swift-600.0.54.20)
Target: x86_64-apple-darwin14.0.0

xcrun swiftc -O SwiftSort.swift
./SwiftSort    
Elapsed time: 1.02204304933548

斯威夫特1.2

1
2
3
4
5
6
7
xcrun swiftc --version
Apple Swift version 1.2 (swiftlang-602.0.49.6 clang-602.0.49)
Target: x86_64-apple-darwin14.3.0

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort    
Elapsed time: 0.738763988018036

斯威夫特2

1
2
3
4
5
6
7
xcrun swiftc --version
Apple Swift version 2.0 (swiftlang-700.0.59 clang-700.0.72)
Target: x86_64-apple-darwin15.0.0

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort    
Elapsed time: 0.767306983470917

如果我用-Ounchecked编译,它的性能似乎是相同的。

斯威夫特3

1
2
3
4
5
6
7
8
9
10
11
xcrun swiftc --version
Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38)
Target: x86_64-apple-macosx10.9

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort    
Elapsed time: 0.939633965492249

xcrun -sdk macosx swiftc -Ounchecked SwiftSort.swift
./SwiftSort    
Elapsed time: 0.866258025169373

从Swift 2.0到Swift 3.0,似乎已经出现了性能回归,我也首次看到了-O-Ounchecked之间的差异。

斯威夫特4

1
2
3
4
5
6
7
8
9
10
11
xcrun swiftc --version
Apple Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)
Target: x86_64-apple-macosx10.9

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort    
Elapsed time: 0.834299981594086

xcrun -sdk macosx swiftc -Ounchecked SwiftSort.swift
./SwiftSort    
Elapsed time: 0.742045998573303

Swift 4再次提高了性能,同时保持了-O-Ounchecked之间的差距。-O -whole-module-optimization似乎没有什么不同。

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 <chrono>
#include <iostream>
#include <vector>
#include <cstdint>
#include <stdlib.h>

using namespace std;
using namespace std::chrono;

int main(int argc, const char * argv[]) {
    const auto arraySize = 10000000;
    vector<uint32_t> randomNumbers;

    for (int i = 0; i < arraySize; ++i) {
        randomNumbers.emplace_back(arc4random_uniform(arraySize));
    }

    const auto start = high_resolution_clock::now();
    sort(begin(randomNumbers), end(randomNumbers));
    const auto end = high_resolution_clock::now();

    cout << randomNumbers[0] <<"
";
    cout <<"Elapsed time:" << duration_cast<duration<double>>(end - start).count() <<"
";

    return 0;
}

结果:

苹果叮当6

1
2
3
4
5
6
7
8
clang++ --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort    
Elapsed time: 0.688969

苹果叮当声6.1.0

1
2
3
4
5
6
7
8
clang++ --version
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort    
Elapsed time: 0.670652

苹果叮当声7.0.0

1
2
3
4
5
6
7
8
clang++ --version
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin15.0.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort    
Elapsed time: 0.690152

苹果叮当声8.0.0

1
2
3
4
5
6
7
8
clang++ --version
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort    
Elapsed time: 0.68253

苹果叮当声9.0.0

1
2
3
4
5
6
7
8
clang++ --version
Apple LLVM version 9.0.0 (clang-900.0.38)
Target: x86_64-apple-darwin16.7.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort    
Elapsed time: 0.736784

判决

在撰写本文时,SWIFT的排序速度很快,但还没有用EDCOX1(10)那样编译时C++的排序速度快。在EDCOX1〔9〕中,其在SWIFT 4.0.2和苹果LLVM 90.0中表现为与C+一样快。


来自The Swift Programming Language

The Sort Function Swift’s standard library provides a function called
sort, which sorts an array of values of a known type, based on the
output of a sorting closure that you provide. Once it completes the
sorting process, the sort function returns a new array of the same
type and size as the old one, with its elements in the correct sorted
order.

sort函数有两个声明。

允许您指定比较结束的默认声明:

1
func sort<T>(array: T[], pred: (T, T) -> Bool) -> T[]

第二个声明只接受一个参数(数组)并"硬编码以使用小于比较器"。

1
2
3
4
func sort<T : Comparable>(array: T[]) -> T[]

Example:
sort( _arrayToSort_ ) { $0 > $1 }

我在一个添加了闭包的操场上测试了一个修改过的代码版本,这样我就可以更紧密地监视函数了,我发现当n设置为1000时,闭包被调用了大约11000次。

1
2
3
4
5
6
let n = 1000
let x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = random()
}
let y = sort(x) { $0 > $1 }

它不是一个有效的函数,我建议使用更好的排序函数实现。

编辑:

我看了一下QuickSort维基百科页面,并为它编写了一个快速的实现。这是我(在操场上)使用的完整程序

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
29
30
31
32
33
34
35
36
37
38
import Foundation

func quickSort(inout array: Int[], begin: Int, end: Int) {
    if (begin < end) {
        let p = partition(&array, begin, end)
        quickSort(&array, begin, p - 1)
        quickSort(&array, p + 1, end)
    }
}

func partition(inout array: Int[], left: Int, right: Int) -> Int {
    let numElements = right - left + 1
    let pivotIndex = left + numElements / 2
    let pivotValue = array[pivotIndex]
    swap(&array[pivotIndex], &array[right])
    var storeIndex = left
    for i in left..right {
        let a = 1 // <- Used to see how many comparisons are made
        if array[i] <= pivotValue {
            swap(&array[i], &array[storeIndex])
            storeIndex++
        }
    }
    swap(&array[storeIndex], &array[right]) // Move pivot to its final place
    return storeIndex
}

let n = 1000
var x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = Int(arc4random())
}

quickSort(&x, 0, x.count - 1) // <- Does the sorting

for i in 0..n {
    x[i] // <- Used by the playground to display the results
}

用这个n=1000,我发现

  • QuickSort()被调用了大约650次,
  • 进行了约6000次互换,
  • 还有大约10000个比较
  • 似乎内置排序方法是(或接近)快速排序,并且非常缓慢…


    从xcode 7开始,可以打开Fast, Whole Module Optimization。这会立即提高你的表现。

    enter image description here


    重新访问Swift阵列性能:

    我写了自己的基准比较swift和c/objective-c。我的基准计算质数。它使用以前质数的数组来查找每个新候选项中的质数因子,因此速度相当快。但是,它执行大量的数组读取,而对数组的写入较少。

    我最初是根据Swift 1.2进行基准测试的。我决定更新这个项目,并使用Swift2.0运行它。

    该项目允许您在使用普通swift数组和使用使用数组语义的swift不安全内存缓冲区之间进行选择。

    对于c/objective-c,您可以选择使用nsarray,或者使用c malloc'ed数组。

    测试结果似乎与最快、最小的代码优化([-0s])或最快、积极的([-0fast))优化非常相似。

    关闭代码优化后,Swift2.0的性能仍然很糟糕,而C/Objective-C的性能只是稍微慢一点。

    归根结底,C malloc的基于数组的计算速度最快,幅度适中。

    使用最快、最小的代码优化时,带不安全缓冲区的swift比C malloc数组长1.19x-1.20x。在快速、积极的优化过程中,两者之间的差别似乎要小一些(Swift比C长1.18x到1.16x)。

    如果使用常规的Swift数组,与C的差异会稍大一些。(斯威夫特需要大约1.22到1.23的时间。)

    常规的Swift数组比Swift 1.2/Xcode 6中的更快。它们的性能与基于快速不安全缓冲区的数组非常接近,以至于使用不安全的内存缓冲区似乎不再值得再麻烦了,这是一个很大的问题。

    顺便说一句,客观的C NSARRAY性能差。如果您要在两种语言中使用本机容器对象,那么Swift将显著加快速度。

    你可以在Github的swiftPerformanceBenchmark上查看我的项目

    它有一个简单的用户界面,可以很容易地收集统计数据。

    有趣的是,在Swift中排序似乎比现在的C略快,但是这个素数算法在Swift中仍然更快。


    其他人提到的主要问题是,-O3在swift中根本不起作用(而且从未起作用),因此在编译时,它实际上是非优化的(-Onone)。

    选项名随时间而变化,因此其他一些答案的构建选项具有过时的标志。正确的当前选项(Swift 2.2)是:

    1
    2
    3
    -Onone // Debug - slow
    -O     // Optimised
    -O -whole-module-optimization //Optimised across files

    整个模块优化的编译速度较慢,但可以跨模块内的文件进行优化,即在每个框架内和实际应用程序代码内进行优化,但不能在它们之间进行优化。您应该将其用于任何关键性能的应用)

    您还可以禁用安全检查,以获得更高的速度,但所有断言和前提条件不仅禁用,而且在正确的基础上进行了优化。如果你有过断言,这意味着你的行为不明确。使用时要格外小心,只有当您确定提速对您有价值时(通过测试)。如果您发现它对某些代码有价值,我建议将该代码分离到一个单独的框架中,并且只禁用该模块的安全检查。


    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
    29
    30
    31
    32
    func partition(inout list : [Int], low: Int, high : Int) -> Int {
        let pivot = list[high]
        var j = low
        var i = j - 1
        while j < high {
            if list[j] <= pivot{
                i += 1
                (list[i], list[j]) = (list[j], list[i])
            }
            j += 1
        }
        (list[i+1], list[high]) = (list[high], list[i+1])
        return i+1
    }

    func quikcSort(inout list : [Int] , low : Int , high : Int) {

        if low < high {
            let pIndex = partition(&list, low: low, high: high)
            quikcSort(&list, low: low, high: pIndex-1)
            quikcSort(&list, low: pIndex + 1, high: high)
        }
    }

    var list = [7,3,15,10,0,8,2,4]
    quikcSort(&list, low: 0, high: list.count-1)

    var list2 = [ 10, 0, 3, 9, 2, 14, 26, 27, 1, 5, 8, -1, 8 ]
    quikcSort(&list2, low: 0, high: list2.count-1)

    var list3 = [1,3,9,8,2,7,5]
    quikcSort(&list3, low: 0, high: list3.count-1)

    这是我关于快速排序的博客-Github示例快速排序

    在对列表进行分区时,您可以查看lomuto的分区算法。用Swift写的


    swift 4.1引入了新的-Osize优化模式。

    In Swift 4.1 the compiler now supports a new optimization mode which
    enables dedicated optimizations to reduce code size.

    The Swift compiler comes with powerful optimizations. When compiling
    with -O the compiler tries to transform the code so that it executes
    with maximum performance. However, this improvement in runtime
    performance can sometimes come with a tradeoff of increased code size.
    With the new -Osize optimization mode the user has the choice to
    compile for minimal code size rather than for maximum speed.

    To enable the size optimization mode on the command line, use -Osize
    instead of -O.

    进一步阅读:https://swift.org/blog/osize/