我想知道朱莉娅的不变类型和表演.
在哪种情况下,使复合类型不可变提高性能?文件说
在某些情况下,它们更有效.上面的Complex示例之类的类型可以有效地打包到数组中,在某些情况下,编译器可以避免完全分配不可变对象.
我真的不明白第二部分.
是否存在使复合类型不可变降低性能的情况(超出需要通过引用更改字段的情况)?我想一个例子可能是当一个不可变类型的对象被重复用作参数时,因为
具有不可变类型的对象通过复制传递(在赋值语句和函数调用中),而可变类型通过引用传递.
但是,我在一个简单的例子中找不到任何区别:
abstract MyType
type MyType1 <: MyType
v::Vector{Int}
end
immutable MyType2 <: MyType
v::Vector{Int}
end
g(x::MyType) = sum(x.v)
function f(x::MyType)
a = zero(Int)
for i in 1:10_000
a += g(x)
end
return a
end
x = fill(one(Int), 10_000)
x1 = MyType1(x)
@time f(x1)
# elapsed time: 0.030698826 seconds (96 bytes allocated)
x2 = MyType2(x)
@time f(x2)
# elapsed time: 0.031835494 seconds (96 bytes allocated)
Run Code Online (Sandbox Code Playgroud)
那么为什么f不变的类型不慢?是否存在使用不可变类型使代码变慢的情况?
不可变类型在它们较小时特别快,并且完全由立即数据组成,没有对堆分配对象的引用(指针).例如,由两个Ints 组成的不可变类型可能存储在寄存器中,根本不存在于内存中.
知道值不会改变也有助于我们优化代码.例如,您x.v在循环内部访问,并且因为x.v将始终引用相同的向量,我们可以在循环外提升它的负载,而不是在每次迭代时重新加载.然而,您是否从中获得任何好处取决于该负载是否占用了循环中的大部分时间.
在实践中很少有不可变的代码减慢代码,但有两种情况可能会发生.首先,如果你有一个很大的不可变类型(比如说100 Int秒)并做一些事情,比如在需要多次移动它们的地方排序它们的数组,额外的复制可能比指向带引用的对象慢.其次,不可变对象通常最初不在堆上分配.如果需要将堆引用存储到一个(例如,在Any数组中),我们需要将对象移动到堆中.从那里,编译器通常不够智能,无法重用对象的堆分配版本,因此可能会重复复制它.在这种情况下,预先堆积分配单个可变对象会更快.