1.Swift中數(shù)組性能的對(duì)比
編寫性能要求高的算法時(shí)调俘,發(fā)現(xiàn)Swift對(duì)使用Array還是ContiguousArray葵孤;使用Class或者Struct作為元素咏尝,都會(huì)對(duì)性能帶來(lái)明顯的影響茎匠。
對(duì)于"向數(shù)組增加元素"的操作岭辣,對(duì)性能提升起占主導(dǎo)作用的是要使用Struct。
而對(duì)于"獲取數(shù)組中的元素"财著,使用ContiguousArray是最敏感的因素联四。
如果算法跟數(shù)組操作十分相關(guān),遇到性能不理想時(shí)撑教,在條件允許的情況下首先應(yīng)該用ContiguousArray替換Array朝墩。其次再考慮數(shù)據(jù)結(jié)構(gòu)是Class改為用Struct。
附上性能測(cè)試代碼
static let LogName = "swift"
public class MyPoint {
public var X :Float = 0
public var Y :Float = 0
}
public struct MyPointStruct {
public var X :Float = 0
public var Y :Float = 0
}
public static func testAll(){
let startTime1 = CFAbsoluteTimeGetCurrent()
//float_multi_test()
let endTime1 = CFAbsoluteTimeGetCurrent()
let diff1:Double = (endTime1 - startTime1) * 1000
print(LogName + " 浮點(diǎn)乘法 " + String(diff1))
//-------------------------------
let startTime2 = CFAbsoluteTimeGetCurrent()
element_add()
let endTime2 = CFAbsoluteTimeGetCurrent()
let diff2:Double = (endTime2 - startTime2) * 1000
print(LogName + " 數(shù)組增加元素 " + String(diff2))
let startTime2_a = CFAbsoluteTimeGetCurrent()
element_add_contiguousArray()
let endTime2_a = CFAbsoluteTimeGetCurrent()
let diff2_a:Double = (endTime2_a - startTime2_a) * 1000
print(LogName + " 數(shù)組增加元素contiguous " + String(diff2_a))
let startTime2_b = CFAbsoluteTimeGetCurrent()
element_add_struct()
let endTime2_b = CFAbsoluteTimeGetCurrent()
let diff2_b:Double = (endTime2_b - startTime2_b) * 1000
print(LogName + " 數(shù)組增加元素struct " + String(diff2_b))
let startTime2_c = CFAbsoluteTimeGetCurrent()
element_add_contiguousArray_struct()
let endTime2_c = CFAbsoluteTimeGetCurrent()
let diff2_c:Double = (endTime2_c - startTime2_c) * 1000
print(LogName + " 數(shù)組增加元素contiguous_struct " + String(diff2_c))
//-------------------------------
let startTime3 = CFAbsoluteTimeGetCurrent()
element_get()
let endTime3 = CFAbsoluteTimeGetCurrent()
let diff3:Double = (endTime3 - startTime3) * 1000
print(LogName + " 數(shù)組獲取元素 " + String(diff3))
let startTime3_a = CFAbsoluteTimeGetCurrent()
element_get_contiguousArray()
let endTime3_a = CFAbsoluteTimeGetCurrent()
let diff3_a:Double = (endTime3_a - startTime3_a) * 1000
print(LogName + " 數(shù)組獲取元素contiguous " + String(diff3_a))
let startTime3_b = CFAbsoluteTimeGetCurrent()
element_get_struct()
let endTime3_b = CFAbsoluteTimeGetCurrent()
let diff3_b:Double = (endTime3_b - startTime3_b) * 1000
print(LogName + " 數(shù)組獲取元素struct " + String(diff3_b))
let startTime3_c = CFAbsoluteTimeGetCurrent()
element_get_contiguousArray_struct()
let endTime3_c = CFAbsoluteTimeGetCurrent()
let diff3_c:Double = (endTime3_c - startTime3_c) * 1000
print(LogName + " 數(shù)組獲取元素contiguous " + String(diff3_c))
}
//浮點(diǎn)乘法
public static func float_multi_test(){
let times = 5999999
var result:Float = 1
for _ in 0 ..< times {
for i in 2 ..< 999 {
result = Float(1/Float(i)+0.5) * result + 0.5
}
}
print(result)
}
//集合增加元素
public static func element_add(){
let times = 5000
var array = [MyPoint]()
for _ in 0 ..< times {
array = [MyPoint]()
for i in 1 ..< 9999 {
let p = MyPoint()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
}
print(array.count)
}
//集合增加元素struct
public static func element_add_struct(){
let times = 5000
var array = [MyPointStruct]()
for _ in 0 ..< times {
array = [MyPointStruct]()
for i in 1 ..< 9999 {
var p = MyPointStruct()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
}
print(array.count)
}
//集合增加元素contiguous
public static func element_add_contiguousArray(){
let times = 5000
var array = ContiguousArray<MyPoint>()
for _ in 0 ..< times {
array = ContiguousArray<MyPoint>()
for i in 1 ..< 9999 {
let p = MyPoint()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
}
print(array.count)
}
//集合增加元素contiguous_struct
public static func element_add_contiguousArray_struct(){
let times = 5000
var array = ContiguousArray<MyPointStruct>()
for _ in 0 ..< times {
array = ContiguousArray<MyPointStruct>()
for i in 1 ..< 9999 {
var p = MyPointStruct()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
}
print(array.count)
}
//集合獲取元素
public static func element_get(){
let times = 5000
var array = [MyPoint]()
for i in 1 ..< 9999 {
let p = MyPoint()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
var result:Float = 0
for _ in 0 ..< times {
for i in 2 ..< 9999 {
let p = array[i-2]
let m = array[i-1]
result = result + p.X + p.Y + m.X + m.Y
}
}
print(result)
}
//集合獲取元素contiguous
public static func element_get_contiguousArray(){
let times = 5000
var array = ContiguousArray<MyPoint>()
for i in 1 ..< 9999 {
let p = MyPoint()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
var result:Float = 0
for _ in 0 ..< times {
for i in 2 ..< 9999 {
let p = array[i-2]
let m = array[i-1]
result = result + p.X + p.Y + m.X + m.Y
}
}
print(result)
}
//集合獲取元素struct
public static func element_get_struct(){
let times = 5000
var array = [MyPointStruct]()
for i in 1 ..< 9999 {
var p = MyPointStruct()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
var result:Float = 0
for _ in 0 ..< times {
for i in 2 ..< 9999 {
let p = array[i-2]
let m = array[i-1]
result = result + p.X + p.Y + m.X + m.Y
}
}
print(result)
}
//集合獲取元素contiguous_struct
public static func element_get_contiguousArray_struct(){
let times = 5000
var array = ContiguousArray<MyPointStruct>()
for i in 1 ..< 9999 {
var p = MyPointStruct()
p.X = (Float(i) - 1 )/Float(i)
p.Y = p.X * 1/Float(i)
array.append(p)
}
var result:Float = 0
for _ in 0 ..< times {
for i in 2 ..< 9999 {
let p = array[i-2]
let m = array[i-1]
result = result + p.X + p.Y + m.X + m.Y
}
}
print(result)
}
記錄一次實(shí)戰(zhàn)效果大概是這樣的
1)沒(méi)有改善前伟姐,算法運(yùn)行耗時(shí)【124s】
2)改用ContiguousArray后收苏,算法運(yùn)行耗時(shí)【60s】
3)在ContiguousArray的基礎(chǔ)上再把關(guān)鍵數(shù)據(jù)類型改用Struct,運(yùn)行耗時(shí)變成【50s】
我想這樣的結(jié)果應(yīng)該和大部分算法的調(diào)優(yōu)過(guò)程會(huì)很接近愤兵,畢竟通常情況下讀取數(shù)組比寫數(shù)組的操作頻率要高鹿霸,那么ContiguousArray的使用會(huì)顯得更要緊一些。
2.Swift和ObjectC在乘法和數(shù)組操作上的對(duì)比
在安卓開(kāi)發(fā)時(shí)秆乳,高性能要求的部分可能就不會(huì)再用java實(shí)現(xiàn)了懦鼠。所以對(duì)于性能優(yōu)先的情況下钻哩,ios開(kāi)發(fā)平臺(tái)選擇哪種開(kāi)發(fā)語(yǔ)言也需要做個(gè)決斷。
性能測(cè)試代碼還是跟上面貼的那段一樣肛冶,改用ObjectC實(shí)現(xiàn)街氢。
簡(jiǎn)單測(cè)試得出的結(jié)論是,Swift用來(lái)寫算法問(wèn)題不大睦袖。
Swift的乘法性能比Object稍差珊肃,但是集合操作有優(yōu)勢(shì)。不過(guò)這也取決于ObjectC的集合操作用法馅笙。鑒于題目是高性能要求的算法是否要ObjectC改寫Swift伦乔,這里已經(jīng)基本得到大致結(jié)論,ObjectC應(yīng)該不會(huì)提升相對(duì)于Swift幾何倍數(shù)的性能延蟹。所以不是非常極限的情況下评矩,用Swift寫算法是可以的。
3.Swift和Java在乘法和數(shù)組操作上的對(duì)比
最后再把鄙人經(jīng)常干的事情阱飘,就是各個(gè)平臺(tái)移植算法需要考慮的一個(gè)測(cè)試也做了。自從Swift產(chǎn)生虱颗,看到的都是好評(píng)一片沥匈。私以為,那是以O(shè)bjectC為參照的罷了忘渔。測(cè)試邏輯還是一樣高帖,最前面貼出的代碼Swift翻版Java實(shí)現(xiàn)。結(jié)論大概就是下圖這樣的畦粮。
這里Swift的添加和獲取元素的操作散址,用的是它最快的組合ContiguousArray+Struct了。
在這樣簡(jiǎn)單的測(cè)試用例下宣赔, Swift還是能看到Java的車尾燈预麸。性能有差距,對(duì)于這樣的新語(yǔ)言來(lái)說(shuō)請(qǐng)繼續(xù)等待它的發(fā)展儒将。
最近一次Swift發(fā)展的后果就是吏祸,鄙人在不改算法的情況下,升級(jí)了系統(tǒng)版本和XCode钩蚊,把Swift3升級(jí)到Swift3.3贡翘,結(jié)果就是性能下降10%。不管是OS有升級(jí)還是是Xcode有升級(jí)砰逻,反正都是蘋果的鍋鸣驱。我只能說(shuō)慶幸不是Swift當(dāng)主打語(yǔ)言的開(kāi)發(fā)者,對(duì)于是的人蝠咆,你們辛苦了踊东。