我尝试使用大型整数数组和大型Bool数组执行Sieve Of Eratosthenes算法。
整数版本似乎比布尔值更快地执行MUCH。可能的原因是什么?
import Foundation
var n : Int = 100000000;
var prime = [Bool](repeating: true, count: n+1)
var p = 2
let start = DispatchTime.now()
while((p*p)<=n)
{
if(prime[p] == true)
{
var i = p*2
while (i<=n)
{
prime[i] = false
i = i + p
}
}
p = p+1
}
let stop = DispatchTime.now()
let time = (Double)(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1000000.0
print("Time = \(time) ms")
布尔数组执行时间:78223.342295 ms
import Foundation
var n : Int = 100000000;
var prime = [Int](repeating: 1, count: n+1)
var p = 2
let start = DispatchTime.now()
while((p*p)<=n)
{
if(prime[p] == 1)
{
var i = p*2
while (i<=n)
{
prime[i] = 0
i = i + p
}
}
p = p+1
}
let stop = DispatchTime.now()
let time = (Double)(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1000000.0
print("Time = \(time) ms")
整数数组执行时间:8535.54546 ms
答案 0 :(得分:1)
(部分回答......)
正如@MartinR在他对这个问题的评论中提到的那样,如果你为发布模式构建(有优化),这两种情况之间没有这么大的区别; Bool
案例因内存占用较小而略快(但同样快,例如UInt8
具有相同的占用空间。)
运行仪器来分析(非优化的)调试版本,我们清楚地看到数组元素访问&amp;赋值是Bool
案例的罪魁祸首(就我的简短测试所见;对于除整数之外的所有类型,Int
,UInt16
等等。
我们可以进一步确定它不是特别是产生开销的写入部分,而是重复访问<{1}}元素的。
对于整数元素数组的相同显式读访问测试显示没有如此大的开销。
在使用调试构建配置进行编译时,由于某种原因,随机元素访问似乎无法正常工作(对于非整数类型)。
答案 1 :(得分:1)
TL,DR:
Int
比Bool
更快,但在通过Profiler运行时,对话是真的。首先,让我们重构代码以便于执行:
func useBoolArray(n: Int) {
var prime = [Bool](repeating: true, count: n+1)
var p = 2
while((p*p)<=n)
{
if(prime[p] == true)
{
var i = p*2
while (i<=n)
{
prime[i] = false
i = i + p
}
}
p = p+1
}
}
func useIntArray(n: Int) {
var prime = [Int](repeating: 1, count: n+1)
var p = 2
while((p*p)<=n)
{
if(prime[p] == 1)
{
var i = p*2
while (i<=n)
{
prime[i] = 0
i = i + p
}
}
p = p+1
}
}
现在,在Debug build中运行它:
let count = 100_000_000
let start = DispatchTime.now()
useBoolArray(n: count)
let boolStop = DispatchTime.now()
useIntArray(n: count)
let intStop = DispatchTime.now()
print("Bool array:", Double(boolStop.uptimeNanoseconds - start.uptimeNanoseconds) / Double(NSEC_PER_SEC))
print("Int array:", Double(intStop.uptimeNanoseconds - boolStop.uptimeNanoseconds) / Double(NSEC_PER_SEC))
// Bool array: 70.097249517
// Int array: 8.439799614
所以Bool
比Int
慢对吗?让我们按Cmd + I
并通过Profiler运行它,然后选择时间配置文件模板。 (不知何故,Profiler无法分离这些功能,可能是因为它们被内联,因此每次尝试只需要运行1个功能):
let count = 100_000_000
useBoolArray(n: count)
// useIntArray(n: count)
// Bool: 1.15ms
// Int: 2.36ms
不仅它们比Debug更快一个数量级,但结果反转为:Bool
现在更快而不是Int
! Profiler并没有告诉我们为什么我们必须如何进行猎巫。让我们通过添加分配工具来检查内存分配:
哈!现在差异很大了。 Bool
数组仅使用与Int
数组一样多的内存。 Swift数组使用与NSArray
相同的内部结构,因此它在堆上分配并且heap allocation很慢。
当你更多地思考它时:Bool
值只占用1位,Int
占用64位机器上的64位。 Swift可能已选择用单个字节表示Bool
,而Int
则需要8个字节,因此存储器比率。在Debug中,这种差异可能会造成所有差异,因为运行时必须进行各种检查以确保它实际处理Bool
值,因此Bool
数组方法需要更长的时间
本课程的道德:不要在调试模式下优化代码。这可能会产生误导!