在this页面上,它说方法push!()
和append!()
非常有效。
我的问题是它们的效率如何?
即,
如果一个知道最终数组的大小,那么预先分配数组还是使用append!()
/ push!()
增量增长它会更快吗?
现在考虑一个不知道最终数组大小的情况。例如,将多个数组合并为一个大数组(称之为A
)。
实现这一目标的两种方法:
append!()
- 将每个数组都放到A
,其大小尚未预先分配。A
的最终大小。然后预分配A
并复制每个数组的内容。在这种情况下哪一个会更有效率?
答案 0 :(得分:13)
这样一个问题的答案通常是:“这取决于”。例如,您想要制作什么尺寸的阵列?数组的元素类型是什么?
但是,如果您只是在启发式之后,为什么不进行简单的速度测试呢?例如,以下代码段:
function f1(N::Int)
x = Array(Int, N)
for n = 1:N
x[n] = n
end
return(x)
end
function f2(N::Int)
x = Array(Int, 0)
for n = 1:N
push!(x, n)
end
return(x)
end
f1(2)
f2(2)
N = 5000000000
@time f1(N)
@time f2(N)
表明使用push!
比预分配慢约6倍。如果您使用append!
添加步数较少的较大块,则乘数几乎肯定会更少。
在解释这些数字时,抵制“什么!?慢6倍!?”的膝跳反应。这个数字需要放在数组构建对整个程序/函数/子程序的重要性的上下文中。例如,如果数组构建只包含例程运行时的1%(对于大多数典型例程,数组构建将包含 小于1%),那么如果例程运行100秒,1秒钟用于构建阵列。乘以6得到6秒。 99秒+6秒= 105秒。因此,使用push!
而不是预分配会使整个程序的运行时间增加5%。除非你在高频交易中工作,否则你可能不会关心它。
对于我自己,我通常的规则是:如果我可以轻松预分配,那么我预先分配。但是如果push!
使例程更容易编码,引入错误的可能性更小,并且更少考虑预先确定适当的数组大小,那么我会毫不犹豫地使用push!
。 / p>
最后注意事项:如果您想真正了解push!
工作原理的详细信息,则需要深入研究C例程,因为julia source只包含ccall
更新: OP在评论中质疑push!
与MATLAB中array(end+1) = n
之类的操作之间的差异。我最近没有在MATLAB中编码,但是我在我的机器上保留了一份副本,因为我所有旧论文的代码都在MATLAB中。我目前的版本是R2014a。我的理解是,在这个版本的MATLAB中,添加到数组的末尾将重新分配整个数组。相比之下,据我所知,朱莉娅的push!
与.NET
中的列表非常相似。随着向量的大小增加,分配给向量的存储器被动态地添加到块中。这大大减少了需要执行的重新分配的数量,虽然我的理解是仍然需要一些重新分配(我很高兴在这一点上得到纠正)。所以push!
应该比在Matlab中添加数组更快 。所以我们可以运行以下MATLAB代码:
N = 10000000;
tic
x = ones(N, 1);
for n = 1:N
x(n) = n;
end
toc
N = 10000000;
tic
x = [];
for n = 1:N
x(end+1) = n;
end
toc
我明白了:
Elapsed time is 0.407288 seconds.
Elapsed time is 1.802845 seconds.
所以,大约减速5倍。鉴于在时序方法中应用了极端的非严格性,人们可能会试图说这相当于朱莉娅案例。但是等等,如果我们用N = 10000000
在朱莉娅重新进行练习,时间是0.01和0.07秒。这些数字的大小与MATLAB数字的巨大差异让我非常担心对实际发生的事情做出声明,以及将MATLAB中的5倍减速与6倍减速进行比较是否合理。朱莉娅。基本上,我现在已经超出了我的深度。也许有人更了解MATLAB实际上做了什么,可以提供更多的见解。关于朱莉娅,我不是一个C编码器,所以我怀疑通过查看源代码可以获得更多的洞察力(与MATLAB不同,这是公开的。)
答案 1 :(得分:13)
push!
总是比插入预先分配的数组慢,如果除了push!
(1)之外没有其他原因插入元素,就像手动执行时一样,(2) )增加数组的长度。当一个操作是两个操作的一部分时,两个操作不能快于一个操作。
然而,正如其他答案中所指出的那样,差距通常不会大到需要关注的事情。在内部(我上次检查代码时),Julia使用了一个2因子增长策略,因此您只需要log2(N)
重新分配。
如果您事先知道数组的大小,可以使用sizehint!
来消除重新分配。由于您可以轻松地自行测试,这并不能消除相对于插入预分配数组的性能损失,但它可以减少它。