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 초가 걸립니다 .
파이썬에서는 0.6 초가 걸립니다 (정수 목록은 y = sorted (x)).
Swift에서는 다음 명령으로 컴파일하면 6 초가 걸립니다 .
xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`
그리고 다음 명령으로 컴파일하면 88 초가 걸립니다 .
xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`
“릴리스”와 “디버그”빌드를 사용한 Xcode의 타이밍은 비슷합니다.
여기서 무엇이 잘못 되었습니까? C ++과 비교할 때 약간의 성능 손실을 이해할 수는 있지만 순수한 Python과 비교할 때 10 배의 속도 저하는 아닙니다.
편집 : 날씨에 따라이 코드를 C ++ 버전만큼 빠르게 실행 하도록 변경 -O3
했습니다 -Ofast
! 그러나 -Ofast
언어의 의미를 많이 변경했습니다. 필자의 테스트에서는 정수 오버플로 및 배열 인덱싱 오버플로 검사를 비활성화했습니다 . 예를 들어, -Ofast
다음 Swift 코드를 사용 하면 충돌없이 자동으로 실행되고 일부 가비지가 인쇄됩니다.
let n = 10000000
print(n*n*n*n*n)
let x = [Int](repeating: 10, count: n)
print(x[n])
그래서 -Ofast
우리가 원하는 것이 아니다; 스위프트의 요점은 안전망이 있다는 것입니다. 물론 안전망은 성능에 약간의 영향을 주지만 프로그램 속도를 100 배 느리게 만들면 안됩니다. Java는 이미 배열 경계를 검사하고 일반적인 경우 속도가 2보다 훨씬 작은 것을 기억하십시오. Clang과 GCC -ftrapv
에서는 정수 오버플로를 검사 (서명)해야하며 느리지 않습니다.
따라서 질문 : 안전망을 잃지 않고 어떻게 Swift에서 합리적인 성능을 얻을 수 있습니까?
편집 2 : 라인을 따라 매우 간단한 루프로 벤치마킹을 더했습니다.
for i in 0..<n {
x[i] = x[i] ^ 12345678
}
(여기서 xor 연산은 어셈블리 코드에서 관련 루프를 더 쉽게 찾을 수 있도록하기 위해 존재합니다. 나는 확인하기가 쉽지만 관련 점검이 필요하지 않다는 의미에서 “무해한”연산을 선택하려고했습니다. 정수 오버플로로.)
다시 사이의 성능에 큰 차이가 -O3
하고 -Ofast
. 그래서 어셈블리 코드를 살펴 보았습니다.
-
와
-Ofast
나는 거의 내가 기대하는 것을 얻을. 관련 부품은 5 개의 기계 언어 지침이있는 루프입니다. -
함께
-O3
나는 나의 거칠은 상상을 넘어서는 무언가를 얻을. 내부 루프는 88 줄의 어셈블리 코드에 걸쳐 있습니다. 모든 것을 이해하려고하지는 않았지만 가장 의심스러운 부분은 “callq _swift_retain”의 13 번의 호출과 “callq _swift_release”의 또 다른 13 번의 호출입니다. 즉 , 내부 루프에서 26 개의 서브 루틴 호출 !
편집 3 : 의견에서, Ferruccio는 빌트인 기능 (예 : 정렬)에 의존하지 않는다는 의미에서 공정한 벤치 마크를 요구했습니다. 다음 프로그램은 상당히 좋은 예라고 생각합니다.
let n = 10000
var x = [Int](repeating: 1, count: n)
for i in 0..<n {
for j in 0..<n {
x[i] = x[j]
}
}
산술이 없으므로 정수 오버플로에 대해 걱정할 필요가 없습니다. 우리가하는 유일한 것은 단지 많은 배열 참조입니다. 결과는 다음과 같습니다. 스위프트 -O3은 -Ofast와 비교하여 거의 500 배나 손실됩니다.
- C ++ -O3 : 0.05 초
- C ++ -O0 : 0.4 초
- 자바 : 0.2 초
- PyPy가 포함 된 Python : 0.5 초
- 파이썬 : 12 초
- 신속-고속 : 0.05 초
- 스위프트 -O3 : 23 초
- 스위프트 -O0 : 443s
(컴파일러가 무의미한 루프를 완전히 최적화 할 것을 우려하는 경우이를 루프로 변경하고 x[i] ^= x[j]
출력을 출력하는 print 문을 추가 할 수 있습니다 x[0]
. 이것은 변경되지 않습니다. 타이밍은 매우 유사합니다.)
그리고 그렇습니다. 여기서 파이썬 구현은 정수 목록과 중첩 된 for 루프가있는 어리석은 순수한 파이썬 구현이었습니다. 최적화되지 않은 스위프트보다 훨씬 느려 야합니다 . Swift 및 배열 인덱싱으로 인해 심각한 문제가 발생한 것 같습니다.
편집 4 : 이 문제 (및 다른 성능 문제)는 Xcode 6 베타 5에서 수정 된 것으로 보입니다.
정렬을 위해 다음 타이밍이 있습니다.
- clang ++ -O3 : 0.06 초
- swiftc-고속 : 0.1 초
- swiftc -O : 0.1 초
- swiftc : 4 초
중첩 루프의 경우 :
- clang ++ -O3 : 0.06 초
- swiftc-고속 : 0.3 초
- swiftc -O : 0.4 초
- swiftc : 540 초
더 이상 안전하지 않은 것을 사용할 이유가없는 것 같습니다 -Ofast
(일명 -Ounchecked
). plain -O
은 똑같이 좋은 코드를 생성합니다.
답변
tl; dr Swift 1.0은 기본 릴리스 최적화 수준 [-O]을 사용하여이 벤치 마크에서 C만큼 빠릅니다.
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.
n = 10_000에 대해 [-Onone] 인 시간 (초) :
Swift: 0.895296452
C: 0.001223848
다음은 n = 10_000에 대한 Swift의 내장 sort ()입니다 .
Swift_builtin: 0.77865783
n = 10_000에 대한 [-O] 는 다음과 같습니다 .
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
비교를 위해 n = 1_000_000의 경우 [-Onone] 과 같습니다 .
Swift: 142.659763258
C: 0.162065333
Swift_sort: 114.095478272
따라서 최적화가없는 Swift는이 개발 단계 에서이 벤치 마크에서 C보다 거의 1000 배 느 렸습니다. 반면에 두 컴파일러 모두 [-Ofast]로 설정 한 경우 Swift는 실제로 C보다 약간 나쁘지 않은 경우에도 실제로 수행되었습니다.
[-Ofast]는 언어의 의미를 변경하여 잠재적으로 안전하지 않은 것으로 지적되었습니다. 이것이 Xcode 5.0 릴리스 노트에서 Apple이 말한 내용입니다.
LLVM에서 사용할 수있는 새로운 최적화 수준 -Ofast는 적극적인 최적화를 가능하게합니다. -Ofast는 대부분의 코드에 안전한 대부분의 부동 소수점 연산에 대한 일부 보수적 인 제한을 완화합니다. 컴파일러의 성능이 크게 향상 될 수 있습니다.
그들은 모두 그것을 옹호합니다. 그것이 현명한 지 아닌지는 말할 수 없지만, 내가 말할 수있는 것에서 고정밀 부동 소수점 산술을하지 않고 정수가 없거나 프로그램에서 배열 오버플로가 가능합니다. 고성능 및 오버플로 검사 / 정확한 산술 이 필요한 경우 지금 다른 언어를 선택하십시오.
베타 3 업데이트 :
[-O]를 사용한 n = 10_000 :
Swift: 0.019697268
C: 0.000718064
Swift_sort: 0.002094721
Swift는 일반적으로 약간 빠르며 Swift의 내장 정렬이 상당히 크게 변경된 것처럼 보입니다.
최종 업데이트 :
[-온원] :
Swift: 0.678056695
C: 0.000973914
[-O] :
Swift: 0.001158492
C: 0.001192406
[-확인되지 않음] :
Swift: 0.000827764
C: 0.001078914
답변
TL; DR은 : 네, 유일한 스위프트 언어 구현은 느린 지금 . 빠른 숫자 (및 다른 유형의 코드, 아마도) 코드가 필요한 경우 다른 코드를 사용하십시오. 앞으로는 선택을 다시 평가해야합니다. 그러나 더 높은 수준으로 작성된 대부분의 응용 프로그램 코드에는 충분할 수 있습니다.
내가 SIL과 LLVM IR에서보고있는 것에서, 보유 및 릴리스를 제거하기위한 많은 최적화가 필요한 것처럼 보입니다. 이것은 Clang (Objective-C의 경우) 으로 구현 될 수 있지만 아직 포팅되지 않았습니다. 이 질문의 마지막 테스트 사례에서 프로파일 러를 실행하면 다음과 같은“예쁜”결과를 얻을 수 있기 때문에 이것이 제가 지금 가지고있는 이론입니다 (현재로서는 Clang이 이에 대해 무언가를 수행하고 있음을 확인해야합니다).
많은 사람들이 말했듯이, -Ofast
완전히 안전하지 않으며 언어 의미를 변경합니다. 저에게는“이 언어를 사용하려면 다른 언어 만 사용하십시오”단계에 있습니다. 나중에 선택 사항이 변경되면 다시 평가하겠습니다.
-O3
우리에게 한 무리의 도착 swift_retain
과 swift_release
그들이이 예를 들어이 있어야처럼, 정직하게, 보이지 않는 전화를. 옵티마이 저는 어레이에 대한 대부분의 정보를 알고 있으며 (적어도) 그것에 대한 강력한 참조를 가지고 있기 때문에 AFAICT를 제거해야합니다.
객체를 해제 할 수있는 함수를 호출하지 않아도 더 많은 보유를 방출해서는 안됩니다. 배열 생성자가 요청 된 것보다 작은 배열을 반환 할 수 있다고 생각하지 않습니다. 즉, 방출 된 많은 검사가 쓸모가 없다는 것을 의미합니다. 또한 정수가 10k를 초과 하지 않기 때문에 오버플로 검사 를 최적화 할 수 있습니다 (이상하지 않기 때문에가 -Ofast
아니라 언어의 의미론으로 인해 var에 변경하거나 액세스 할 수 없으며 최대 10k를 추가하는 것은 없습니다) 유형에 안전합니다 Int
).
그러나 컴파일러는 배열 또는 배열 요소의 압축을 풀지 못할 수도 있습니다 sort()
. 외부 함수 인으로 전달되어 예상 한 인수를 가져와야하기 때문입니다. 이렇게하면 Int
값을 간접적으로 사용해야하므로 조금 느려집니다. sort()
컴파일러가 범용 함수가 아닌 일반 함수를 사용할 수 있고 인라인 된 경우 변경 될 수 있습니다 .
이것은 아주 새로운 (공개적으로) 언어이며, 피드백을 요청 스위프트 언어와 관련된 (크게) 사람들이 있기 때문에 그것은, 내가 생각 무엇을 통해 많은 변화가되는 것입니다 그들은 모든 언어가 완료되지 않습니다 말하고 것이다 변화.
사용 된 코드 :
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")
추신 : 저는 Objective-C 또는 Cocoa , Objective-C 또는 Swift 런타임의 모든 시설에 대한 전문가가 아닙니다 . 내가 쓰지 않은 것들을 가정하고있을 수도 있습니다.
답변
나는 이것을 재미있게 살펴보기로 결정했고, 다음과 같은 타이밍을 얻었습니다.
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()
결과 :
스위프트 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
스위프트 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
스위프트 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
.
스위프트 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
있습니다.
스위프트 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
간극 유지하면서 신속한 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;
}
결과 :
애플 클랜 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
애플 클랜 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
애플 클랜 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
애플 클랑 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
애플 클랑 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
평결
이 글을 쓰는 시점에서 Swift의 정렬은 빠르지 만 -O
위 컴파일러 및 라이브러리를 사용하여 컴파일 할 때 C ++ 정렬만큼 빠르지는 않습니다 . 을 사용하면 -Ounchecked
Swift 4.0.2 및 Apple LLVM 9.0.0에서 C ++만큼 빠릅니다.
답변
보낸 사람 The Swift Programming Language
:
Sort Function Swift의 표준 라이브러리는 sort라는 함수를 제공합니다. sort라는 함수는 사용자가 제공 한 정렬 클로저의 출력을 기반으로 알려진 유형의 값 배열을 정렬합니다. 정렬 프로세스가 완료되면 sort 함수는 요소가 올바른 정렬 순서로 이전 유형과 크기 및 크기가 같은 새 배열을 반환합니다.
이 sort
함수에는 두 가지 선언이 있습니다.
비교 클로저를 지정할 수있는 기본 선언 :
func sort<T>(array: T[], pred: (T, T) -> Bool) -> T[]
그리고 하나의 매개 변수 (배열) 만 사용하고 “보다 작은 비교기를 사용하도록 하드 코딩 된”두 번째 선언입니다.
func sort<T : Comparable>(array: T[]) -> T[]
Example:
sort( _arrayToSort_ ) { $0 > $1 }
클로저가 추가 된 놀이터에서 수정 된 코드 버전을 테스트하여 기능을 좀 더 자세히 모니터링 할 수 있었고 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) { $0 > $1 }
효율적인 기능이 아니므로 더 나은 정렬 기능 구현을 사용하는 것이 좋습니다.
편집하다:
Quicksort wikipedia 페이지를보고 Swift 구현을 작성했습니다. 내가 사용한 전체 프로그램은 다음과 같습니다 (놀이터에서).
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 개의 교환이 이루어졌으며
- 약 10,000 개의 비교가 있습니다
내장 정렬 방법이 빠른 정렬 (또는 가까운) 인 것처럼 보이며 실제로 느립니다 …
답변
Xcode 7부터는을 켤 수 있습니다 Fast, Whole Module Optimization
. 성능이 즉시 향상됩니다.
답변
스위프트 어레이 성능 재검토 :
Swift와 C / Objective-C를 비교 한 자체 벤치 마크를 작성했습니다. 내 벤치 마크는 소수를 계산합니다. 이전 소수의 배열을 사용하여 각 새 후보에서 소수를 찾습니다. 따라서 매우 빠릅니다. 그러나 배열 읽기의 TONS를 수행하고 배열에 쓰기를 줄입니다.
원래 Swift 1.2에 대해이 벤치 마크를 수행했습니다. 프로젝트를 업데이트하고 Swift 2.0에서 실행하기로 결정했습니다.
이 프로젝트를 통해 일반적인 빠른 배열 사용과 배열 의미론을 사용하는 Swift 안전하지 않은 메모리 버퍼 사용 중에서 선택할 수 있습니다.
C / Objective-C의 경우 NSArray 또는 C malloc’ed 배열을 사용하도록 선택할 수 있습니다.
테스트 결과는 가장 빠르고 작은 코드 최적화 ([-0s]) 또는 가장 빠르고 공격적인 ([-0fast]) 최적화와 매우 유사 해 보입니다.
C / Objective-C 성능은 약간 느리지 만 Swift 2.0 성능은 여전히 코드 최적화가 꺼져있어 끔찍합니다.
결론적으로 C malloc의 배열 기반 계산은 완만 한 마진으로 가장 빠릅니다.
안전하지 않은 버퍼가있는 스위프트는 가장 빠르고 작은 코드 최적화를 사용할 때 C malloc의 어레이보다 1.19X-1.20X 더 오래 걸립니다. 빠르고 공격적인 최적화에서는 차이가 약간 줄어 듭니다 (Swift는 C보다 1.18x에서 1.16x 더 오래 걸립니다.
일반 Swift 배열을 사용하는 경우 C와의 차이가 약간 큽니다. (Swift는 ~ 1.22 ~ 1.23 시간이 더 걸립니다.)
레귤러 스위프트 어레이는 DRAMATICALLY
Swift 1.2 / Xcode 6보다 속도 빠릅니다. 성능이 Swift 안전하지 않은 버퍼 기반 어레이에 너무 가깝기 때문에 안전하지 않은 메모리 버퍼를 사용하는 것이 더 이상 문제의 가치가없는 것처럼 보입니다.
BTW, Objective-C NSArray 성능에 악영향을 미칩니다. 당신이 두 언어의 기본 컨테이너 개체를 사용하려고하는 경우, 스위프트는 DRAMATICALLY 빨리.
SwiftPerformanceBenchmark 에서 github의 프로젝트를 확인할 수 있습니다
통계를 매우 쉽게 수집 할 수있는 간단한 UI가 있습니다.
Swift에서는 C보다 정렬이 약간 빠르지 만 Swift에서는이 소수 알고리즘이 여전히 빠르다는 점이 흥미 롭습니다.
답변
다른 사람들이 언급했지만 충분히 언급되지 않은 주요 문제는 -O3
Swift에서 전혀 아무것도하지 않으며 결코 가지고 있지 않으므로 실제로 컴파일되지 않을 때 효과적으로 최적화되지 않는 것입니다 ( -Onone
).
옵션 이름은 시간이 지남에 따라 변경되었으므로 다른 답변에는 빌드 옵션에 대한 플래그가 더 이상 사용되지 않습니다. 올바른 현재 옵션 (Swift 2.2)은 다음과 같습니다.
-Onone // Debug - slow
-O // Optimised
-O -whole-module-optimization //Optimised across files
전체 모듈 최적화는 컴파일 속도가 느리지 만 모듈 내의 파일, 즉 각 프레임 워크 내 및 실제 응용 프로그램 코드 내에서 파일간에 최적화 할 수는 없습니다. 중요한 성능을 위해서는 이것을 사용해야합니다)
더 빠른 속도를 위해 안전 검사를 비활성화 할 수 있지만 모든 어설 션 및 사전 조건은 비활성화 될뿐만 아니라 정확한 기준에 따라 최적화됩니다. 만약 당신이 주장에 부딪쳤다면 이것은 당신이 정의되지 않은 행동을하고 있다는 것을 의미합니다. 테스트를 통해 속도 향상이 가치가 있다고 판단되는 경우에만 각별히주의하십시오. 일부 코드에서 유용하다고 생각되면 해당 코드를 별도의 프레임 워크로 분리하고 해당 모듈에 대한 안전 검사 만 비활성화하는 것이 좋습니다.