Arrays 整数与布尔数组的Swift性能
我尝试使用一个大整数数组和一个大布尔数组执行Eratosthenes算法的筛选Arrays 整数与布尔数组的Swift性能,arrays,swift,int,boolean,Arrays,Swift,Int,Boolean,我尝试使用一个大整数数组和一个大布尔数组执行Eratosthenes算法的筛选 整数版本的执行速度似乎比布尔版本快得多。可能的原因是什么 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)
整数版本的执行速度似乎比布尔版本快得多。可能的原因是什么
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")
<代码>导入基础
变量n:Int=100000000;
var prime=[Bool](重复:true,计数:n+1)
var p=2
让我们开始=DispatchTime.now()
而((p*p)(部分答案…)
正如@MartinR在对问题的评论中提到的,如果您构建为发布模式(带有优化),那么这两种情况之间没有如此大的区别;Bool
情况稍微快一些,因为它的内存占用更小(但与具有相同占用空间的UInt8
一样快)
运行工具来分析(非优化的)调试构建,我们清楚地看到数组元素访问和分配是Bool
案例的罪魁祸首(就我简短的测试所见,对于除整数类型以外的所有类型,Int
,UInt16
,等等)
我们可以进一步确定,产生开销的不是特别是写入部分,而是重复访问i:th
元素
对于整数元素数组的相同显式读访问测试显示没有如此大的开销
在使用调试构建配置进行编译时,似乎出于某种原因,随机元素访问没有正常工作(对于非整数类型)。(部分答案…)
正如@MartinR在对问题的评论中提到的,如果您构建为发布模式(带有优化),那么这两种情况之间没有如此大的区别;Bool
情况稍微快一些,因为它的内存占用更小(但与具有相同占用空间的UInt8
一样快)
运行工具来分析(非优化的)调试构建,我们清楚地看到数组元素访问和分配是Bool
案例的罪魁祸首(就我简短的测试所见,对于除整数类型以外的所有类型,Int
,UInt16
,等等)
我们可以进一步确定,产生开销的不是特别是写入部分,而是重复访问i:th
元素
对于整数元素数组的相同显式读访问测试显示没有如此大的开销
在使用调试构建配置进行编译时,似乎出于某种原因,随机元素访问无法正常工作(对于非整数类型)。TL,DR:
- 不要尝试在调试生成中优化代码。始终通过探查器运行代码。
在调试中比Int
更快,但在通过探查器运行时,oposite为trueBool
- 堆分配是昂贵的。明智地使用内存。(在C中讨论了复杂性,但也适用于Swift)
长话短说 首先,让我们重构代码以便于执行:
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
}
}
所以Bool
比Int
慢很多对吧?让我们通过按Cmd+I
在探查器中运行它,并选择时间配置文件模板。(不知何故探查器无法分离这些函数,可能是因为它们是内联的,所以每次尝试只能运行1个函数):
它们不仅比调试快一个数量级,而且结果相反:Bool
现在比Int
快一个数量级!!!探查器没有告诉我们为什么必须进行政治迫害。让我们通过添加分配工具来检查内存分配:
哈!现在差别已经暴露出来了。Bool
数组只使用了Int
数组八分之一的内存。Swift数组使用了与NSArray
相同的内部结构,因此它被分配到堆上,速度很慢
仔细想想:一个Bool
值只占用1位,一个Int
值在64位机器上占用64位。Swift可能选择用一个字节表示Bool
,而Int
值占用8个字节,因此内存比率。在调试中,这个差异可能会导致所有的差异,因为runtime必须进行各种检查,以确保它实际处理的是Bool
值,因此Bool
数组方法所需的时间要长得多
这一课的寓意是:不要在调试模式下优化代码。这可能会产生误导!TL,DR:
- 不要尝试在调试生成中优化代码。始终通过探查器运行代码。
在调试中比Int
更快,但在通过探查器运行时,oposite为trueBool
- 堆分配是昂贵的。明智地使用内存。(在C中讨论了复杂性,但也适用于Swift)
长话短说 首先,让我们重构代码以便于执行:
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
}
}
所以Bool
比Int
慢很多对吧?让我们通过按Cmd+I
在探查器中运行它,并选择时间配置文件模板。(不知何故探查器无法分离这些函数,可能是因为它们是内联的,所以每次尝试只能运行1个函数):
它们不仅比调试快一个数量级,而且结果相反:Bool
现在比Int
快一个数量级!!!探查器没有告诉我们为什么必须进行政治迫害。让我们通过添加分配工具来检查内存分配:
哈!现在差别已经暴露出来了。Bool
数组只使用了Int
数组八分之一的内存。Swift数组使用了与NSArray
相同的内部结构,因此它被分配到堆上,速度很慢
当你
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
let count = 100_000_000
useBoolArray(n: count)
// useIntArray(n: count)
// Bool: 1.15ms
// Int: 2.36ms