我试图加快代码中的主要瓶颈。它是将数组元素插入数组的中间。这些元素必须一次插入一个,因为我事先并不知道。我无法收集它们并立即将它们全部插入,因为稍后出现的元素(以及它们的插入位置)以复杂的方式依赖于更新的数组。
我推测速度限制是由于两个因素造成的:(1)矢量一次生长一个元素,以及(2)复制所有需要向右碰撞的元素插入元素。因子#2有点简化,因为我怀疑在插入新元素时整个更新的矢量是完整的。我不认为我有解决因素#2的解决方案,但我确实尝试了因素#1的一些可能性 - 即预分配。以下测试表明,我尝试的替代方法无法改进我当前的方法(无预分配)。测试使用内部循环迭代地将新元素插入到数组的位置2中。 out循环只需重复执行此测试100次,以获得更好的定时统计数据。
clc; Ntests=1e4;
disp('1) Pre-allocate, update vector in-place without creating new array.')
tic
for j = 1 : Ntests
clear a
a(100) = 0;
a(1)=1;
for i = 2:100
a(3:end) = a(2:99);
a(2) = i;
end % i
end % j
toc
disp('2) Pre-allocate, copy & create new array by concatenation.')
tic
for j = 1 : Ntests
clear a
a(100) = 0;
a(1)=1;
for i = 2:100
a = [ a(1) i a(2:end-1) ];
end % i
end % j
toc
disp('3) No pre-allocation (current method).')
tic
for j = 1 : Ntests
clear a
a(1)=1;
for i = 2:100
a = [ a(1) i a(2:end) ];
end % i
end % j
toc
结果是:
1) Pre-allocate, update vector in-place without creating new array.
Elapsed time is 2.359021 seconds.
2) Pre-allocate, copy & create new array by concatenation.
Elapsed time is 4.221047 seconds.
3) No pre-allocation (current method).
Elapsed time is 2.248106 seconds.
这种情况真的像这样令人沮丧,还是我可以对瓶颈做些什么呢?
问题的背景:
每个双数组表示机器的时间线,双精度数表示使用期间的开始时间。结束时间存储在另一个双数组中。对于每个使用期限,除了开始时间和结束时间之外还有其他字段。所以我有一些数组,每个字段一个。
当我获得一段时间的新需求时,它是一个值集合的形式,每个字段一个,我必须看它是否适合时间轴(我有其他逻辑来确定,我也正试图加速)。如果它不合适,我会转到另一个时间轴再试一次。如果没有现有的时间表可以容纳新需求的开始到结束时间,我会创建另一台具有空白时间轴的计算机。
假设一段使用时间由N个字段组成,其中开始和结束时间是这些字段中的两个。每个时间轴表示为N个数组,而不是N个字段的结构数组。这是因为经验测试和网上冲浪表明N个标量数组的操作速度比N个字段的单个结构数组更快。但是,如果我必须更新N个标量数组只是为了插入一个使用期限,这可能不再适用,我还没有测试过。 (我修改了使用数组字段从struct数组迁移到struct的代码,并且需要一些时间才能返回)。
上面的代码仅用于测试插入数组中间的开销。它并不意味着模拟本上下文部分中描述的整个问题。
请注意,我在下面的评论中同意这是一个优先级队列问题。这假设每个新的使用期已经由我的其他逻辑确定以适应时间线,然后将开始时间视为优先级。然而,经过反思,它并不是一个完全优先级队列问题,因为我实际上并没有将任何东西从队列中拉出来直到最后。因此,它简化了优先级队列的使用,以建立时间表。
虽然我还没有为优先级队列选择和合并公开可用的Matlab代码,但我仍然不太有信心会有净加速。这是因为在Matlab中调用函数的速度很慢,并且每个时间线在完全构建时平均包含不到六个使用期(至少对于当前的问题集)。因此,与调用函数来更新优先级队列相比,简单插入很可能是构建时间轴的最快方式。当我有机会尝试时,我会更新这个问题。