swift - 是否对所有结构进行写时快速复制?

标签 swift value-type copy-on-write

我知道 swift 会优化数组的写入时复制,但它会为所有结构执行此操作吗?例如:

struct Point {
   var x:Float = 0
}

var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data

最佳答案

Array实现的写时复制行为——无论编译器优化如何,你都会得到它(当然,优化可以减少情况的数量需要复制的地方)。

在基本层面上,Array 只是一个结构,它包含对包含元素的堆分配缓冲区的引用——因此多个 Array 实例可以引用 相同缓冲区。当您要改变给定的数组实例时,实现将检查缓冲区是否被唯一引用,如果是,则直接改变它。否则,数组将执行底层缓冲区的副本以保留值语义。

但是,对于您的 Point 结构,您并未在语言级别实现写时复制。当然,如@Alexander says ,这不会阻止编译器执行各种优化以最小化复制整个结构的成本。不过,这些优化不需要完全遵循写时复制的行为——只要程序按照语言规范运行,编译器就可以自由地做它想做的事。

在您的特定示例中,p1p2 都是全局的,因此编译器需要使它们成为不同的实例,因为同一模块中的其他 .swift 文件可以访问对他们来说(尽管这可以通过整个模块优化来优化)。然而,编译器仍然不需要复制实例——它可以只需要evaluate the floating-point addition at compile-time。并用 0.0 初始化其中一个全局变量,用 1.0 初始化另一个全局变量。

如果它们是函数中的局部变量,例如:

struct Point {
    var x: Float = 0
}

func foo() {
    var p1 = Point()
    var p2 = p1
    p2.x += 1
    print(p2.x)
}

foo()

编译器甚至不必创建两个 Point 实例开始——它可以只创建一个初始化为 1.0 的浮点局部变量,然后打印那个。

关于将值类型作为函数参数传递,对于足够大的类型和(在结构的情况下)充分利用其属性的函数,编译器 can pass them by reference而不是复制。然后,被调用者可以仅在需要时制作它们的副本,例如需要使用可变副本时。

在结构按值传递的其他情况下,编译器也有可能 specialise functions为了只复制函数需要的属性。

对于下面的代码:

struct Point {
    var x: Float = 0
    var y: Float = 1
}

func foo(p: Point) {
    print(p.x)
}

var p1 = Point()
foo(p: p1)

假设 foo(p:) 没有被编译器内联(在这个例子中它会内联,但是一旦它的实现达到一定的大小,编译器就不会认为它值得) –编译器可以将函数特化为:

func foo(px: Float) {
    print(px)
}

foo(px: 0)

它只将 Pointx 属性的值传递给函数,从而节省了复制 y 属性的成本。

所以编译器会尽其所能减少值类型的复制。但是,由于在不同情况下进行了如此多的优化,您不能简单地将任意值类型的优化行为归结为写时复制。

关于swift - 是否对所有结构进行写时快速复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43486408/

相关文章:

ios - 不希望导航和选项卡出现在初始 ViewController 上

swift - 为什么不能为计算属性定义属性观察器?

ios - 当遇到 subview (UIStackView > ContainerView)时,UIScrollView 停止垂直滚动

ios - FaSTLane:使用在配置文件中设置配置文件的 GYM

Swift:闭包如何捕获值类型的变量?

kubernetes - kubernetes pod 的写时复制式内存重用?使 pod 生成速度更快、内存效率更高

java - 如何从 Java 中的 CopyOnWriteArrayList 中获取底层静态数组?

c# - MonoTouch 从 subview 设置位置

c# - 如果结构是值类型,为什么我可以新建它?

python - NumPy 数组写时复制