Производительность Swift Beta: сортировка массивов

я реализовывал алгоритм в Swift Beta и заметил, что производительность была очень низкой. Копнув глубже, я понял, что одним из узких мест было что-то простое, как сортировка массивов. Соответствующая часть здесь:

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.06 s на моем компьютере.

в Python это занимает 0.6 s (без трюков, просто y = сортировка (x) для списка целых чисел).

в Swift это занимает 6s если я скомпилирую его со следующей командой:

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

и это 88s если я скомпилирую его со следующей командой:

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

тайминги в Xcode с построениями" Release "и" Debug " похожи.

что здесь не так? Я мог бы понять некоторую потерю производительности по сравнению с C++, но не 10-кратное замедление по сравнению с чистым Python.


Edit: mweathers заметил, что меняется -O3 to -Ofast делает этот код работать почти так же быстро, как C++ версии! Однако,-Ofast изменяет семантику языка много - в моем тестировании это отключены проверки переполнения целых чисел и переполнения индексирования массива. Например, с -Ofast следующий Swift-код работает бесшумно без сбоев (и печатает некоторый мусор):

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

так -Ofast это не то, что мы хотим; весь смысл Swift в том, что у нас есть сетки безопасности на месте. Конечно, сети безопасности оказывают некоторое влияние на производительность, но они не должны замедлять программы в 100 раз. Помните, что Java уже проверяет границы массива,и в типичных случаях замедление в два раза меньше. И в Clang и GCC мы получили -ftrapv для проверки (подписанного) переполнения целого числа, и это тоже не так медленно.

следовательно, вопрос: как мы можем получить разумную производительность в Swift без потери безопасности сетками?


Edit 2: я сделал еще несколько бенчмаркинга, с очень простыми петлями по линиям

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 вызовов подпрограмм во внутреннем цикле!


Edit 3: в комментариях Ферруччо попросил критерии, которые справедливы в том смысле, что они не полагаются на встроенные функции (например, сортировка). Я думаю, что следующая программа является довольно хорошим примером:

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

нет арифметики, поэтому нам не нужно беспокоиться о переполнении целых чисел. Единственное, что мы делаем это просто много ссылок на массив. И результаты здесь-Swift-O3 проигрывает почти в 500 раз по сравнению с-Ofast:

  • C++ - O3: 0.05 s
  • C++ - O0: 0.4 s
  • Java: 0.2 s
  • Python с PyPy: 0.5 s
  • Python: 12 s
  • Swift-Ofast: 0.05 s
  • Swift-O3: 23 s
  • Swift-O0: 443 s

(если вас беспокоит, что компилятор может полностью оптимизировать бессмысленные циклы, вы можете изменить его на, например,x[i] ^= x[j], и добавьте оператор печати, который выводит x[0]. Это ничего не меняет; тайминги будут очень похожи.)

и да, здесь реализация Python была глупой чистой реализацией Python со списком ints и вложенными циклами for. Он должен быть!--24-->много медленнее, чем неоптимизированный Swift. Что-то кажется будьте серьезно нарушены с помощью Swift и индексации массива.


Edit 4: эти проблемы (а также некоторые другие проблемы с производительностью), похоже, были исправлены в Xcode 6 beta 5.

для сортировки, у меня теперь есть следующие тайминги:

  • clang++ - O3: 0.06 s
  • swiftc-Ofast: 0.1 s
  • swiftc-O: 0.1 s
  • swiftc: 4 s

для вложенных петли:

  • clang++ - O3: 0.06 s
  • swiftc-Ofast: 0.3 s
  • swiftc-O: 0.4 s
  • swiftc: 540 s

кажется, что больше нет причин использовать небезопасный -Ofast (a.к. a. -Ounchecked); равнина -O производит одинаково хороший код.

8 ответов


tl; dr Swift 1.0 теперь так же быстро, как C по этому тесту, используя уровень оптимизации выпуска по умолчанию [-O].


вот на месте quicksort в Swift Beta:

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:

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);
}

как работает:

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]

оба вызываются в той же программе, что и написано.

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();

это преобразует абсолютное время в секундах:

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;
}

вот краткое изложение компилятора уровни оптимизации:

[-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.

время в секундах с [- Onone] на n=10_000:

Swift:            0.895296452
C:                0.001223848

вот встроенный сортировка Swift () для n=10_000:

Swift_builtin:    0.77865783

здесь [- O] на n=10_000:

Swift:            0.045478346
C:                0.000784666
Swift_builtin:    0.032513488

как вы можете видеть, производительность Swift улучшилась в 20 раз.

по состоянию на ответ mweathers, настройка [-Ofast] делает реальную разницу, в результате чего в эти времена для n=10_000:

Swift:            0.000706745
C:                0.000742374
Swift_builtin:    0.000603576

и n=1_000_000:

Swift:            0.107111846
C:                0.114957179
Swift_sort:       0.092688548

Для сравнения, это с [- Onone] на n=1_000_000:

Swift:            142.659763258
C:                0.162065333
Swift_sort:       114.095478272

поэтому Swift без оптимизации был почти 1000x медленнее, чем C в этом тесте, на данном этапе его разработки. С другой стороны, оба компилятора установлены в [- Ofast] Swift фактически выполнил по крайней мере так же хорошо, если не немного лучше, чем C.

было указано, что [- Ofast] изменяет семантику языка, что делает его потенциально небезопасным. Это то, что Apple заявляет в примечаниях к выпуску Xcode 5.0:

новый уровень оптимизации-Ofast, доступный в LLVM, позволяет агрессивную оптимизацию. - Ofast ослабляет некоторые консервативные ограничения, в основном для операций с плавающей запятой, которые безопасны для большинства кодов. Он может давать значительные высокопроизводительные выигрыши от компилятора.

они все почти выступают за это. Мудро это или нет, я не мог сказать, но из того, что я могу сказать, кажется достаточно разумным использовать [-Ofast] в выпуске, если вы не делаете высокоточную арифметику с плавающей запятой, и вы уверены, что в вашей программе не возможны переполнения целых чисел или массивов. Если вам нужна высокая производительность и проверки переполнения / точная арифметика затем выберите другой язык пока.

ОБНОВЛЕНИЕ BETA 3:

n=10_000 С [- O]:

Swift:            0.019697268
C:                0.000718064
Swift_sort:       0.002094721

Swift в целом немного быстрее, и похоже, что встроенная сортировка Swift изменилась довольно значительно.

ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ:

[- Onone]:

Swift:   0.678056695
C:       0.000973914

[- O]:

Swift:   0.001158492
C:       0.001192406

[-Ounchecked]:

Swift:   0.000827764
C:       0.001078914

TL; DR: да, единственная реализация языка Swift медленная,прямо сейчас. Если вам нужен быстрый, числовой (и другие типы кода, предположительно) код, просто перейдите к другому. В будущем вам следует пересмотреть свой выбор. Это может быть достаточно хорошо для большинства кода приложения, написанного на более высоком уровне.

из того, что я вижу в SIL и LLVM IR, кажется, что им нужна куча оптимизаций для удаления сохраняет и выбросов, которые могут быть реализованы в лязгом (для Objective-C), но они еще не портировали их. Это теория, с которой я иду (пока... мне все еще нужно подтвердить, что Clang что-то делает с этим), так как профилировщик, запущенный на последнем тестовом примере этого вопроса, дает этот "красивый" результат:

Time profiling on -O3Time profiling on -Ofast

как говорили многие другие, -Ofast полностью небезопасно и изменяет семантику языка. Для меня это на "Если вы собираетесь использовать это, просто используйте другой язык " этап. Я пересмотрю этот выбор позже, если он изменится.

-O3 получает нам кучу swift_retain и swift_release называет это, честно говоря, не похоже, что они должны быть там для этого примера. Оптимизатор должен был исключить (большинство) их AFAICT, поскольку он знает большую часть информации о массиве и знает, что он имеет (по крайней мере) сильную ссылку на него.

он не должен испускать больше сохраняет, когда он даже не вызывает функции что может освободить объекты. Я не думаю, что конструктор массива может вернуть массив, который меньше того, что было запрошено, а это означает, что многие проверки, которые были выпущены, бесполезны. Он также знает, что целое число никогда не будет выше 10k, поэтому переполнение проверяет можете оптимизироваться (не из-за -Ofast странность, но из-за семантики языка (больше ничего не меняется, что var не может получить к нему доступ, и добавление до 10k безопасно для типа Int).

компилятор, возможно, не сможет распаковать массив или элементы массива, поскольку они передаются в sort(), который является внешней функцией и должен получить аргументы, которые он ожидает. Это заставит нас использовать Int значения косвенно, что сделает его немного медленнее. Это может измениться, если sort() generic функция (не в многомодовом способе) была доступна компилятору и была встроена.

это очень новый (публично) язык, и он проходит через то, что я предполагаю, много изменений, так как есть люди (в значительной степени), связанные с языком Swift, запрашивающим обратную связь, и все они говорят, что язык не закончен и будет изменить.

код:

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 ни все средства от какао, Objective-C или быстрое время выполнения. Я также могу предполагать некоторые вещи, которые я не сделал писать.


я решил взглянуть на это для удовольствия, а вот тайминги, которые я получаю:

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

Свифт

// 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()

результаты:

Swift 1.1

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

Swift 1.2

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

Swift 2.0

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.

Swift 3.0

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 впервые.

Swift 4.0

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++

#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] << "\n";
    cout << "Elapsed time: " << duration_cast<duration<double>>(end - start).count() << "\n";

    return 0;
}

результаты:

Apple Clang 6.0

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

Apple Clang 6.1.0

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

Apple Clang 7.0.0

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

Apple Clang 8.0.0

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

Apple Clang 9.0.0

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

приговором

на момент написания этой статьи, вид Свифта быстро, но еще не так быстро, как сортировка C++при компиляции с -O, с вышеуказанными компиляторами и библиотеками. С -Ounchecked, он кажется таким же быстрым, как C++ в Swift 4.0.2 и Apple LLVM 9.0.0.


С The Swift Programming Language:

стандартная библиотека функции сортировки Swift предоставляет функцию под названием сортировка, которая сортирует массив значений известного типа на основе вывод закрытия сортировки, которое вы предоставляете. Как только он завершает процесс сортировки, функция sort возвращает новый массив того же самого тип и размер как старый, с его элементами в правильной сортировке порядок.

на > }

я протестировал измененную версию вашего кода на игровой площадке с добавленным закрытием, чтобы я мог контролировать функцию немного более внимательно, и я обнаружил, что с N, установленным на 1000, закрытие вызывалось около 11,000 раз.

let n = 1000
let x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = random()
}
let y = sort(x) {  >  }

это не эффективная функция, и я бы рекомендовал использовать лучшую реализацию функции сортировки.

EDIT:

Я взглянул на страницу Википедии Quicksort и написал для нее быструю реализацию. Вот полная программа, которую я использовал (на игровой площадке)

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, я обнаружил, что

  1. quickSort () получил вызов около 650 раз,
  2. около 6000 ОСП были сделаны,
  3. и есть около 10 000 сравнений

кажется, что встроенный метод сортировки (или близок к) быстрой сортировки и очень медленный...


начиная с Xcode 7 Вы можете включить Fast, Whole Module Optimization. Это должно немедленно повысить производительность.

enter image description here


производительность Swift Array revisited:

Я написал свой собственный бенчмарк, сравнивая Swift с C / Objective-C. мой бенчмарк вычисляет простые числа. Он использует массив предыдущих простых чисел для поиска простых факторов в каждом новом кандидате, поэтому он довольно быстр. Тем не менее, он делает тонны чтения массива и меньше записи в массивы.

Я изначально сделал этот тест против Swift 1.2. Я решил обновить проект и запустить его против Swift 2.0.

в проект позволяет выбирать между использованием обычных массивов swift и использованием небезопасных буферов памяти Swift с использованием семантики массива.

для C / Objective-C вы можете выбрать использование массивов NSArrays или C malloc'Ed.

результаты теста кажутся довольно похожими с самой быстрой, наименьшей оптимизацией кода ([- 0s]) или самой быстрой, агрессивной ([- 0fast]) оптимизацией.

производительность Swift 2.0 по-прежнему ужасна с отключенной оптимизацией кода, тогда как производительность C / Objective-C только умеренно медленнее.

суть в том, что вычисления на основе массива c malloc'D являются самыми быстрыми, со скромным запасом

Swift с небезопасными буферами занимает около 1.19 X-1.20 X больше, чем массивы c malloc'D при использовании самой быстрой и минимальной оптимизации кода. разница кажется немного меньше с быстрой, агрессивной оптимизацией (Swift занимает больше времени от 1.18 x до 1.16 x, чем C.

Если вы используете регулярные массивы Swift, разница с C немного больше. (Swift занимает ~1.22 до 1.23 дольше.)

регулярные массивы Swift являются DRAMATICALLY быстрее, чем они были в Swift 1.2/в Xcode 6. Их производительность настолько близка к SWIFT unsafe buffer based arrays, что использование небезопасных буферов памяти больше не стоит проблем, что является большим.

кстати, производительность Objective-C NSArray воняет. Если вы собираетесь использовать собственные объекты контейнера на обоих языках, Swift резко быстрее.

вы можете проверить мой проект на GitHub в SwiftPerformanceBenchmark

Он имеет простой интерфейс, который делает сбор статистики довольно легко.

интересно, что сортировка кажется немного быстрее в Swift, чем в C, но этот алгоритм простых чисел все еще быстрее в Swift.


основной вопрос, который упоминается другими, но не вызван достаточно, что -O3 ничего не делает в Swift (и никогда не делал), поэтому при компиляции он эффективно не оптимизирован (-Onone).

имена опций со временем изменились, поэтому некоторые другие ответы имеют устаревшие флаги для параметров сборки. Правильные текущие параметры (Swift 2.2):

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

оптимизация всего модуля имеет более медленную компиляцию, но может оптимизировать файлы внутри модуля, т. е. в каждой структуре и в фактическом коде приложения, но не между ними. Вы должны использовать это для чего-либо критического производительности)

вы также можете отключить проверки безопасности для еще большей скорости, но со всеми утверждениями и предварительными условиями не только отключены, но оптимизированы на основе их правильности. Если вы когда-либо попадали в утверждение, это означает, что вы находитесь в неопределенном поведении. Используйте с предельной осторожностью и только если вы определяете, что повышение скорости стоит для вас (by тестирование.) Если вы считаете это ценным для некоторого кода, я рекомендую разделить этот код на отдельную структуру и отключить только проверки безопасности для этого модуля.


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 быстрый-сортировка

вы можете взглянуть на алгоритм разбиения Ломуто в разбиении списка. Написано в Swift