我有点回答自己的问题,尽管我认为这不是最好的解决方案。由于不熟悉Swift,我认为这可能是我们能做到的最好的方法,但是使用UnsafeMutableRawPointer(mutating:)进行memmove()转换存在潜在的内存分配问题。必须有一种方法来进行转换,否则将该分配插入我的代码中肯定会影响性能。
如果有人知道如何避免对UnsafeMutableRawPointer的转换,请告诉我。
var src: [UInt32] = [1, 2, 3, 4]
var dest: [UInt32] = [0, 0, 0, 0]
let elemSize = MemoryLayout<UInt32>.stride
dest.withUnsafeBytes { (destBuffer: UnsafeRawBufferPointer) in
src.withUnsafeBytes { (srcBuffer: UnsafeRawBufferPointer) in
let destPtr = UnsafeMutableRawPointer(mutating: destBuffer.baseAddress)
let destOffset = destPtr! + elemSize
let srcOffset = srcBuffer.baseAddress! + 0
memmove(destOffset, srcOffset, elemSize * 2)
}
}
print(dest)
编辑 1:现在越来越接近了。显然,replaceSubrange() 比 memmove() 慢得多,实际上慢了6-7倍。相比之下,字节计数越小,replaceSubrange() 的速度就越快。在实际示例中,在执行所有 memmove() 调用之前,您只需要一次获取数组字节,因此实际上比这更快。
replaceSubrange: 0.750978946685791
memmove: 0.139282941818237
func TestMemmove() {
var src: [UInt32] = Array(repeating: 1, count: 1000)
var dest: [UInt32] = Array(repeating: 0, count: 1000)
let elemSize = MemoryLayout<UInt32>.stride
let testCycles = 100000
let rows = 200
var startTime = CFAbsoluteTimeGetCurrent()
for _ in 0..<testCycles {
dest.replaceSubrange(1...1+rows, with: src[0...rows])
}
var endTime = CFAbsoluteTimeGetCurrent()
print("replaceSubrange: \(endTime - startTime)")
startTime = CFAbsoluteTimeGetCurrent()
for _ in 0..<testCycles {
dest.withUnsafeMutableBytes { destBytes in
src.withUnsafeMutableBytes { srcBytes in
let destOffset = destBytes.baseAddress! + elemSize
let srcOffset = srcBytes.baseAddress! + 0
memmove(destOffset, srcOffset, elemSize * rows)
}
}
}
endTime = CFAbsoluteTimeGetCurrent()
print("memmove: \(endTime - startTime)")
}
编辑2:在所有这些愚蠢的事情之后,从C中调用memmove是最快的。Swift将指针传递给数组的第一个元素,然后您可以使用C中的指针算术来处理所需的偏移量,这需要在Swift中进行.withUnsafeXXX调用(这可能分配了一些类包装器)。
结论是Swift很慢,因此在任何性能敏感的代码中都要切换到C。
BlockMove:0.0957469940185547
replaceSubrange:1.89903497695923
memmove:0.136561989784241
void BlockMove (void* dest, int destOffset, const void* src, int srcOffset, size_t count) {
memmove(dest + destOffset, src + srcOffset, count);
}
func TestMemmove() {
var src: [UInt32] = Array(repeating: 1, count: 1000)
var dest: [UInt32] = Array(repeating: 0, count: 1000)
let elemSize = MemoryLayout<UInt32>.stride
let testCycles = 100000
let rows = 500
var startTime: CFAbsoluteTime = 0
var endTime: CFAbsoluteTime = 0
startTime = CFAbsoluteTimeGetCurrent()
for _ in 0..<testCycles {
BlockMove(&dest, Int32(elemSize), &src, 0, Int32(elemSize * rows))
}
endTime = CFAbsoluteTimeGetCurrent()
print("BlockMove: \(endTime - startTime)")
startTime = CFAbsoluteTimeGetCurrent()
for _ in 0..<testCycles {
dest.replaceSubrange(1...1+rows, with: src[0...rows])
}
endTime = CFAbsoluteTimeGetCurrent()
print("replaceSubrange: \(endTime - startTime)")
startTime = CFAbsoluteTimeGetCurrent()
for _ in 0..<testCycles {
dest.withUnsafeMutableBytes { destBytes in
src.withUnsafeMutableBytes { srcBytes in
let destOffset = destBytes.baseAddress! + elemSize
let srcOffset = srcBytes.baseAddress! + 0
memmove(destOffset, srcOffset, elemSize * rows)
}
}
}
endTime = CFAbsoluteTimeGetCurrent()
print("memmove: \(endTime - startTime)")
}
Swift 4.0
。 - TheTiger