【问题标题】:Is there a swiftc compiler optimization to remove unnecessary large variables?是否有 swiftc 编译器优化来删除不必要的大变量?
【发布时间】:2018-05-26 07:53:32
【问题描述】:

当我使用高阶函数编写代码时,我发现像这样一次写出一个转换的表达式会更简洁:

let children = objects.map { $0.children }
let validChildren = children.filter { $0.isValid }
let sortedChildren = validChildren.sorted { $0.count < $1.count }

但是,我知道这些函数中的每一个都返回一个新的 Array 对象,我将其存储到一个变量中,所以理论上我每次都创建并保留一个新的 Array 并浪费大量内存。最好将调用写成一行,以便在使用后销毁不必要的数组。

let sortedChildren = objects.map { $0.children } .filter { $0.isValid } .sorted { $0.count < $1.count }

但是这更烦人,因为在一行代码中发生了很多事情。所以我的问题是:Swift 的编译器是否有优化来原谅我的挑剔并在编译时删除未使用的变量?

【问题讨论】:

  • “一行代码中发生了很多事情” – 请注意,您可以在 .filter.sorted 之前换行 ...
  • 这听起来像是过早的优化。
  • 不,编译器不会关心您将其拆分为不同的变量。但是,如果您担心内存问题,您可以按照@MartinR 所说的那样使用换行符,或者您至少可以将变量声明为私有/文件私有或惰性。
  • 数组也是“写时复制”,这使得未修改的副本“便宜”。 – 如果您的两个版本之间确实存在差异,您是否进行了分析?
  • @MartinR 当然,但这仍然符合单条指令的条件,并且比第一个选项嘈杂得多。但我的问题主要是关于编译器优化。考虑到它相对年轻,我不确定 swiftc 的可用功能。

标签: swift compiler-optimization


【解决方案1】:

@MartinR 在问题 cmets 中提到了这一点,但值得官方回答和来源。

As per the Swift repository docs:

Swift 中的所有标准库容器都是使用 COW 的值类型 (copy-on-write) [4] 执行复制而不是显式复制。在 在很多情况下,这允许编译器通过 保留容器而不是执行深层复制。这是 如果引用计数仅通过复制底层容器来完成 容器的值大于 1 并且容器发生了变异。为了 在下面的例子中,将 d 分配给时不会发生复制 c,但是当 d 通过附加 2 发生结构突变时,d 将是 复制,然后 2 将附加到 d:

var c: [Int] = [ ... ]
var d = c        // No copy will occur here.
d.append(2)      // A copy *does* occur here.

由于高阶函数不会修改它们被调用的对象,因此可以说结果已针对大小进行了优化。

【讨论】:

    【解决方案2】:

    两个版本没有区别。

    即使您不将结果分配给变量,也会创建一个新的列表实例来存储函数调用的结果。因此,内存使用是相同的。

    objects.map { $0.children }.filter { $0.isValid }.sorted { $0.count < $1.count }
    

    所以在每次函数调用之后,我们仍然需要内存来存储该函数的结果,无论您是否将其assign 到变量中。并且assigning 到另一个变量不会复制该对象。

    【讨论】:

      猜你喜欢
      • 2019-06-27
      • 2017-05-04
      • 1970-01-01
      • 2018-11-26
      • 1970-01-01
      • 2013-03-23
      • 2018-12-30
      • 1970-01-01
      • 2012-09-06
      相关资源
      最近更新 更多