为什么Swift在for-in循环中使用下标语法比使用直接访问元素更快?

为什么Swift在for-in循环中使用下标语法比使用直接访问元素更快?,第1张

概述我读了着名的 Why is it faster to process a sorted array than an unsorted array?,我决定玩游戏并尝试其他语言,如Swift.我对2个非常相似的代码片段之间的运行时间差异感到惊讶. 在Swift中,可以在for-in循环中以直接方式或使用下标访问数组中的元素.例如这段代码: for i in 0..<size { sum += 我读了着名的 Why is it faster to process a sorted array than an unsorted array?,我决定玩游戏并尝试其他语言,如Swift.我对2个非常相似的代码片段之间的运行时间差异感到惊讶.

在Swift中,可以在for-in循环中以直接方式或使用下标访问数组中的元素.例如这段代码:

for i in 0..<size {    sum += data[i]}

可写:

for element in data {    sum += element}

随着数据长度和数据的大小,可汇总元素的数组.

所以,我只是在Swift(代码吼叫)中实现了与我在第一段中提到的问题相同的算法,令我惊讶的是第一种方法比第二种方法快大约5倍.

我真的不知道后台下标的实现,但我认为直接访问Swift for-in循环中的元素只是语法糖.

我的问题是两个for-in语法之间的区别是什么以及为什么使用下标更快?

这里是计时器的细节.我在2015年初的MacBook Air上使用Xcode 9.4.1和Swift 4.1以及Commande line项目.

// Using Direct Element AccessElapsed Time: 8.506288427Sum: 1051901000

VS

// Using SubscriptElapsed Time: 1.483967902Sum: 1070388000

额外的问题:为什么Swift中的执行速度比C中慢100倍(在n Xcode项目中都在同一台Mac上执行)?例如,在C中100,000次重复几乎与Swift中的1,000次重复相同.我的第一个猜测是,Swift是一种比C语言更高级的语言,例如Swift运行更多的安全检查.

这是我使用的Swift代码,我只修改了第二个嵌套循环:

import Foundationimport GameplayKitlet size = 32_768var data = [Int]()var sum  = 0var rand = GKRandomdistribution(lowestValue: 0,highestValue: 255)for _ in 0..<size {    data.append(rand.nextInt())}// data.sort()let start = dispatchTime.Now()for _ in 0..<1_000 {    // Only the following for-in loop changes    for i in 0..<size {        if data[i] <= 128 {            sum += data[i]        }    }}let stop     = dispatchTime.Now()let nanoTime = stop.uptimeNanoseconds - start.uptimeNanosecondslet elapsed  = Double(nanoTime) / 1_000_000_000print("Elapsed Time: \(elapsed)")print("Sum: \(sum)")
解决方法 总体性能输出很大程度上取决于编译器所做的优化.如果在启用优化的情况下编译代码,您将看到两个解决方案之间的差异很小.

为了证明这一点,我更新了您的代码,添加了两个方法,一个使用下标,另一个使用for-in.

import Foundationimport GameplayKitlet size = 32_768var data = [Int]()var sum  = 0var rand = GKRandomdistribution(lowestValue: 0,highestValue: 255)for _ in 0..<size {    data.append(rand.nextInt())}// data.sort()func withSubscript() {  let start = dispatchTime.Now()  for _ in 0..<1_000 {      for i in 0..<size {          if data[i] <= 128 {              sum += data[i]          }      }  }  let stop    = dispatchTime.Now()  let elapsed = Double(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000  print("With subscript:")  print("- Elapsed Time: \(elapsed)")  print("- Sum: \(sum)")}func withForIn() {  let start = dispatchTime.Now()  for _ in 0..<1_000 {      for element in data {          if element <= 128 {              sum += element          }      }  }  let stop    = dispatchTime.Now()  let elapsed = Double(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000  print("With for-in:")  print("- Elapsed Time: \(elapsed)")  print("- Sum: \(sum)")}withSubscript()withForIn()

我将该代码保存到名为array-subscripting.swift的文件中.

然后,从命令行,我们可以在没有任何优化的情况下运行它,如下所示:

$swift array-subscripting.swift With subscript:- Elapsed Time: 0.924554249- Sum: 1057062000With for-in:- Elapsed Time: 5.796038213- Sum: 2114124000

正如你在帖子中提到的,性能有很大差异.

使用优化编译代码时,这种差异可以忽略不计:

$swiftc array-subscripting.swift -O$./array-subscripting With subscript:- Elapsed Time: 0.110622556- Sum: 1054578000With for-in:- Elapsed Time: 0.11670454- Sum: 2109156000

如您所见,两种解决方案都比以前更快,并且在时间执行上非常相似.

回到原来的问题,下标提供了对内存的直接访问,这在连续数组的情况下非常有效,其中元素在内存中彼此相邻存储.

另一方面,for-in循环从数组中创建每个元素的不可变副本,这会导致性能损失.

总结

以上是内存溢出为你收集整理的为什么Swift在for-in循环中使用下标语法比使用直接访问元素更快?全部内容,希望文章能够帮你解决为什么Swift在for-in循环中使用下标语法比使用直接访问元素更快?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1008440.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存