是时候进入位数组数组了
Posted
技术标签:
【中文标题】是时候进入位数组数组了【英文标题】:time to get in array of bitarrays 【发布时间】:2019-02-05 06:30:45 【问题描述】:我在那个代码中有一个我不明白的问题:
ilProbekUcz= valuesUcz.Count; //valuesUcz is the list of <float[]>
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)
int index = 0;
linia = (float[])valuesUcz[i];//removing this line not solve problem
for (int a = 0; a < ileRazem; a++)
for (int b = 0; b < ileRazem; b++)
if (a != b)
bool value = linia[a] >= linia[b];
nodesValueArrayUcz[index][i] = value;
nodesValueArrayUcz[ilWezlowDanychP2 + index][i] = !value;
index++;
sw.Stop();
当我将 valuesUcz
的大小增加 2 倍时,执行时间会增加 4 倍
当我将 valuesUcz
的大小增加 4 倍时,执行时间增加了 8 倍
等等……
(ileRazem
,ilWezlowDanych
同理)
我明白:ilProbekUcz
的增加会增加BitArrays
的大小,但我对其进行了多次测试,这没问题 - 时间应该线性增长 - 在代码中:
ilProbekUcz= valuesUcz.Count; //valuesTest is the list of float[]
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
BitArray test1 = nodesValueArrayUcz[10];
BitArray test2 = nodesValueArrayUcz[20];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)
int index = 0;
linia = (float[])valuesUcz[i];//removing this line not solve problem
for (int a = 0; a < ileRazem; a++)
for (int b = 0; b < ileRazem; b++)
if (a != b)
bool value = linia[a] >= linia[b];
test1[i] = value;
test2[i] = !value;
index++;
时间线性增长,所以问题是从数组中取一个BitArray
...
有什么方法可以更快吗? (我希望时间线性增长)
【问题讨论】:
...时间线性增长,所以问题是从数组中取出一个BitArray...有什么方法可以更快地做到这一点吗? (我希望时间增长线性) ... O(1 * n) = O(2 * n) = ... = O(c * n) = O(n ),其中 c 是一个常数。 什么是ileRazem
?
linia 的大小 - 我在 1440、2880、5760 处测量时间
但是“linia”不是问题,我把它变成了一个常数,时间都是一样的
您可以删除linia
并使用bool value = valuesUcz[ i ][ a ] >= valuesUcz[ i ][ b ];
。你说没用。如果你不告诉你想要完成什么,我们无法帮助你。我们只能看到 3 个for
循环在做某事。
【参考方案1】:
您必须了解,测量时间有很多因素导致它们不准确。在您的示例中拥有 huuuuuge 数组时,最大的因素是 cashe misses
。考虑到 cshe 时,写同样的东西很多次,可能会快 2-5 倍或更多倍。两个词 Cashe 的工作原理,非常粗略。缓存是cpu内部的内存。它比 ram 快 waaaaaaaaaaaaaay,所以当你想从内存中获取一个变量时,你要确保这个变量存储在缓存中而不是 ram 中。如果它存储在缓存中,我们说我们有一个hit
,否则是一个miss
。有时,不是经常,一个程序太大以至于它将变量存储在硬盘驱动器中。在这种情况下,当您获取这些时,您会延迟击中 huuuuuuuuuuuge!缓存示例:
假设我们在内存(ram)中有一个包含 10 个元素的数组
当你得到第一个元素 testArray[0]
时,因为 testArray[0] 不在缓存中,cpu 会将这个值 与 一起带上一个数字(比如说 3,数量取决于数组的相邻元素的 cpu) 例如它存储到缓存 testArray[0], testArray[1], testArray[2], testArray[3]
现在当我们得到testArray[1]
时,它在缓存中,所以我们有一个hit
。 testArray[2]
和 testArray[3]
也是如此。 testArray[4]
不在缓存中,所以它会得到 testArray[4]
以及另外 3 个 testArray[5], testArray[6], testArray[7]
等等……
缓存misses
非常昂贵。这意味着您可能期望双倍大小的数组可以访问两倍的时间。但是这是错误的。更大的数组更多misses
并且时间可能会比您预期的时间增加 2 倍或 3 倍或 4 倍或更多倍。这个是正常的。在您的示例中,这就是正在发生的事情。从 1 亿个元素(第一个数组)到 4 亿个(第二个数组)。 misses
不是双倍的,而是你看到的更多。一个非常酷的技巧与访问数组的方式有关。在您的示例中,ba1[j][i] = (j % 2) == 0;
比ba1[i][j] = (j % 2) == 0;
差得多。 ba2[j][i] = (j % 2) == 0;
和 ba1[i][j] = (j % 2) == 0;
也是如此。你可以测试一下。只需反转i and j
。它与二维数组在内存中的存储方式有关,因此在第二种情况下,hits
比第一种情况多。
【讨论】:
谢谢,我知道 ba[i][j] 更快 - 它的时间会线性增长;),算法需要从第一个代码开始按顺序填充它们......我需要考虑一下它 - 但我有一个问题:你知道一些方法让我影响缓存中的内容吗? @barpas 你不能。只要数据是连续的,一个接一个,CPU就会自动执行。在您的循环中,有 99,9999% 的时间浪费在获取缓存值上。因此,如果这些值不是彼此相邻的,那么您就有很大的问题。您必须了解array[0][0]
和array[1][0]
在内存中不在一起。但是array[0][0]
和array[0][1]
是!告诉我你的算法是做什么的,这样我就可以在你的代码中帮助你。
如您所见,有行数组,有值 - 它比较 linie (float[]) 中的每个值并将结果放入适当的位数组,行按时间排序,位数组按时间排序比较值 bitarray 中的每一位是下一个时间段
@barpas 我需要确切的代码,否则我帮不了你以上是关于是时候进入位数组数组了的主要内容,如果未能解决你的问题,请参考以下文章