我正在对Swift和Objective-C进行一些性能测试。
我创建了一个Mac OS混合Swift / Objective-C项目,该项目使用Swift或Objective-C创建大型素数数组。
它有一个不错的用户界面,并以清晰的显示方式显示结果。如果您有兴趣,可以在Github上查看该项目。它被称为SwiftPerformanceBenchmark。
Objective-C代码使用malloc的C int数组,Swift代码使用Array
对象。
因此,目标C代码要快得多。
我已经阅读过使用如下代码在字节缓冲区周围创建类似数组的包装:
let size = 10000
var ptr = UnsafePointer<Int>malloc(size)
var bytes = UnsafeBufferPointer<Int>(start: ptr, count: data.length)
我想修改我的示例程序,以便在运行时使用Array<Int>
存储和UnsafeBufferPointer<Int>
之间切换,并在UI中使用复选框。
因此,我的primes
数组需要一个基本类型,它将包含Array<Int>
或UnsafeBufferPointer<Int>
。我对Swift语法仍然太弱,无法弄清楚如何做到这一点。
对于基于数组的代码,我必须使用array.append(value)
,对于预填充数据的UnsafeBufferPointer<Int>
,我会使用{{1 }}。我想如果必须,我可以使用占位符值预先填充array[index]
对象,这样我就可以使用Array
语法。
有人可以给我一个可以容纳array[index]
或Array<Int>
的基类型,以及在运行时分配任何类型的类型转换吗?
比如说,我有以下内容:
UnsafeBufferPointer<Int>
答案 0 :(得分:4)
@ MartinR的建议应该有助于获得可以在两者之间切换的代码。但是,您可以使用快捷方式来证明Swift数组和C数组之间的性能差异,以及将Swift编译器优化切换为-Ounchecked
的方法。这样做可以消除对使用不安全指针手动执行的数组索引等的边界检查。
如果我从github下载你的项目并且这样做,我发现Objective-C版本的速度是Swift版本的两倍。但是......那是因为sizeof(int)
是4,但sizeof(Int)
是8.如果你切换C版本也使用8字节算术......
P.S。它反过来也是如此,如果我将Swift代码切换为使用UInt32
,它的运行速度是其速度的2倍。
答案 1 :(得分:1)
如果我能正确理解你的问题,我不是100%确定,但也许 这就是你需要的方向。
Array
和UnsafeMutablePointer
都符合MutableCollectionType
(需要下标getter和setter)。
所以这个函数会接受这两种类型:
func foo<T : MutableCollectionType where T.Generator.Element == Int, T.Index == Int>(inout storage : T) {
storage[0] = 1
storage[1] = 2
}
缓冲区指针示例:
let size = 2
var ptr = UnsafeMutablePointer<Int>(malloc(UInt(size * sizeof(Int))))
var buffer = UnsafeMutableBufferPointer<Int>(start: ptr, count: size)
foo(&buffer)
for elem in buffer {
println(elem)
}
数组示例:
var array = [Int](count: 2, repeatedValue: 0)
foo(&array)
for elem in array {
println(elem)
}
对于非变异功能,您可以使用CollectionType
而不是MutableCollectionType
。
答案 2 :(得分:1)
好吧,它不漂亮,但这里有一个泛型函数可以处理任何类型的集合,这意味着你可以传入Array
或UnsafeMutableBufferPointer
,这意味着你可以使用它在malloc的内存范围内,或使用数组的.withUnsafeMutableBufferPointer
。
不幸的是,通用版本的一些必需品使其在阵列上使用时的效率略低于非通用版本。但是当与缓冲区一起使用时,-O
中的数组确实表现出相当不错的性能提升:
func storePrimes<C: MutableCollectionType where C.Generator.Element: IntegerType>(inout store: C) {
if isEmpty(store) { return }
var candidate: C.Generator.Element = 3
var primeCount = store.startIndex
store[primeCount++] = 2
var isPrime: Bool
while primeCount != store.endIndex {
isPrime = true
var oldPrimeCount = store.startIndex
for oldPrime in store {
if oldPrimeCount++ == primeCount { break }
if candidate % oldPrime == 0 { isPrime = false; break }
if candidate < oldPrime &* oldPrime { isPrime = true; break }
}
if isPrime { store[primeCount++] = candidate }
candidate = candidate.advancedBy(2)
}
}
let totalCount = 2_000_000
var primes = Array<CInt>(count: totalCount, repeatedValue: 0)
let startTime = CFAbsoluteTimeGetCurrent()
storePrimes(&primes)
// or…
primes.withUnsafeMutableBufferPointer { (inout buffer: UnsafeMutableBufferPointer<CInt>) -> Void in
storePrimes(&buffer)
}
let now = CFAbsoluteTimeGetCurrent()
let totalTime = now - startTime
println("Total time: \(totalTime), per second: \(Double(totalCount)/totalTime)")