Arrays 整数与布尔数组的Swift性能

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)

我尝试使用一个大整数数组和一个大布尔数组执行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)
    {
        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
    在调试中比
    Bool
    更快,但在通过探查器运行时,oposite为true
  • 堆分配是昂贵的。明智地使用内存。(在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
    在调试中比
    Bool
    更快,但在通过探查器运行时,oposite为true
  • 堆分配是昂贵的。明智地使用内存。(在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