[英]Java: Splitting up a massive 2D array into blocks that are a multiple of the machine's page size
我这样做的原因是,各种不同的线程可以在从相同的2D数组接收信息并写入大小相同的另一个2D数组时,同时执行某些计算。
现在,我了解了如何简单地将数组分解为多个部分,并将每个部分分配给一个线程。 例如,我有8个线程和一个8x8 2D数组。 每个线程负责从一个2D数组中收集所需的信息,然后在另一个2D数组中写入其自己的相应列。 因为没有在第一个2D数组上进行写操作,所以没有理由对那里的线程设置限制,但是有必要在线程也要写的数组上设置限制。 我这方面没有任何问题。
我正在做作业,程序的运行时间很重要。 我的老师建议我们“使该块成为一个处理页面大小倍数的线程”。
我们正在使用两个10000 x 10000 2D阵列,并且机器页面大小为4Kib或4096字节。 我的问题是我不知道如何在我的程序中利用这些信息。 现在,我只是使用布尔数组,但是稍后我将用char数组实现它。
我仅计算多少列等于4096字节的倍数,然后将其除以8个线程? 如何计算2D数组的大小?
编辑:到目前为止,我的程序运行良好,只是异常缓慢。 我应该每秒创建30到60代之间的任意位置,也就是说,在完整的10000 x 10000阵列上进行30到60次完整写入。 不幸的是,我每秒只能写约8张。 现在,每个线程(8个线程中)都在12 500 x 10000个相等大小的块上写入。
最佳布局实际上取决于您的处理过程所展示的访问模式。 通常,您应努力使内存访问模式保持尽可能线性。
首先要注意的是Java将多维数组视为数组数组的方式。 这意味着通过迭代最内层循环中最右边的维度可以最好地实现访问的局部性。 取出循环不变式也可以帮助降低复杂度。 您得到的是这样的:
int[][][] threeD = new int[10][10][10];
for (int x=0; x<threeD.length; ++x) {
int[][] twoD = threeD[x];
for (int y=0; y<twoD.length; ++y) {
int[] oneD = twoD[y];
for (int z=0; z<oneD.length; ++z) {
oneD[z] = // whatever
}
}
}
从这开始,您希望不以“块”为单位来分配工作,而是以连续的切片为目标,例如,对于int [y = 10000] [x = 10000]和4个工作单元,请将外部尺寸划分为4个工作单元,而不是将两个维度都一分为二:
Bad way to slice work: More cache-friendly:
111222 111111
111222 222222
333444 333333
333444 444444
在这样的方案中,TLB大小(页面大小)基本无关。 通过保持尽可能线性的数据访问,无论TLB条目数和页面大小如何,您都会自动将TLB的丢失率降到最低。 这里的目的是使突发存储器访问和/或推测性数据预取的有效性最大化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.