- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有两个二维数组,我想将它们逐个元素求和。两个数组的大小相同,行数和列数也相同)。它应该返回一个最终数组,其大小与逐个元素的总和相同。
如何使用 Java 的 Fork-Join 框架或一般的并行性来完成这样的任务?使用并行性来解决这个问题有意义吗?
下面是我对 Java 的 Fork-Join 框架未完成的尝试:
public class SumArray extends RecursiveTask<int[][]> {
private static final int ROW_CUTOFF = 10;
private static final int COL_CUTOFF = 10;
int[][] left_;
int[][] right_;
int rowLo_;
int rowHi_;
int colLo_;
int colHi_;
SumArray(int[][] left, int[][] right, int rowLo, int rowHi, int colLo, int colHi) {
left_ = left;
right_ = right;
rowLo_ = rowLo;
rowHi_ = rowHi;
colLo_ = colLo;
colHi_ = colHi;
}
@Override
protected int[][] compute() {
if (rowHi_ - rowLo_ <= ROW_CUTOFF && colHi_ - colLo_ <= COL_CUTOFF) {
for (int i = rowLo_; i < rowHi_; i++) {
for (int j = colLo_; j < colHi_; j++) {
left_[i][j] += right_[i][j];
}
}
return left_;
}
int rowMid = rowLo_ + ((rowHi_ - rowLo_) / 2);
int colMid = colLo_ + ((colHi_ - colLo_) / 2);
SumArray topLeft = new SumArray(left_, right_, rowLo_, rowMid, colLo_, colMid);
SumArray topRight = new SumArray(left_, right_, rowMid, rowHi_, colLo_, colMid);
topLeft.fork()
int[][] topRightSummed = topRight.compute();
int[][] topLeftSummed = topLeft.join();
// ???
我可以类似地找到左下角和右下角的数组,但是如何在保持并行性性能的同时连接这些数组?我应该使用共享内存吗?
最佳答案
在抛出线程解决此问题之前,请优化单核的使用。在这种情况下,CPU 缓存未命中会产生明显的差异。例如,考虑此示例代码,在一种情况下,它对 array[i][j] 和另一个 array[j][i] 中的值求和。其中一个的 CPU 缓存未命中次数要少得多,因此比另一个要快得多。以下代码可用于演示该行为。
public class Sum2D {
public static void main( String[] args ) {
int[][] data = createGrid(100);
long sum = 0;
long start1 = System.currentTimeMillis();
for ( int i=0; i<100000; i++ ) {
sum += sumAcrossFirst(data);
}
long end1 = System.currentTimeMillis();
long start2 = System.currentTimeMillis();
for ( int i=0; i<100000; i++ ) {
sum += sumAcrossSecond(data);
}
long end2 = System.currentTimeMillis();
double duration1 = (end1-start1)/1000.0;
double duration2 = (end2-start2)/1000.0;
System.out.println("duration1 = " + duration1);
System.out.println("duration2 = " + duration2);
System.out.println("sum = " + sum);
}
private static int[][] createGrid(int size) {
int[][] data = new int[size][size];
for ( int x=0; x<size; x++ ) {
for ( int y=0; y<size; y++ ) {
data[x][y] = 1;
}
}
return data;
}
private static long sumAcrossFirst(int[][] data) {
long sum = 0;
int size = data.length;
for ( int x=0; x<size; x++ ) {
for ( int y=0; y<size; y++ ) {
sum += data[x][y];
}
}
return sum;
}
private static long sumAcrossSecond(int[][] data) {
long sum = 0;
int size = data.length;
for ( int x=0; x<size; x++ ) {
for ( int y=0; y<size; y++ ) {
sum += data[y][x];
}
}
return sum;
}
}
另一个优化是将 int[][] 减少为 int[],这将减少指针追逐,现代 CPU 预取器将启动并将数组的下一部分保留在缓存中。
为了并行,您必须考虑相同的缓存行为,并认识到使用多个线程会产生开销。因此,较小的数组在单个线程上求和的速度会更快。最好测量此阈值,因为它随 CPU 的不同而变化,但一般来说它会在 1000 左右或更多。也就是说,我通常会等待输入数据通过一百万个单元格,然后再担心额外的复杂性。跨数组求和的速度很快。
对数组求和的最快方法是使用 SIMD 指令,不幸的是,如果不使用 JNI 或类似的东西,它们不能直接在 Java 中使用。 Fork/Join 的工作令人钦佩,但在加快速度之前它有一些开销。这意味着并行和单核需要多少int才能实现收支平衡的阈值会更高。
让多个线程写入同一个单个数组是有意义的。请注意,从多个 CPU 核心写入可能会导致核心之间的缓存失效,如果有两个单独的核心访问同一内存页,则可能会导致系统抖动。
因此,为了开始工作,您可以随意使用以下方法。它演示了如何使用 Java Executor;这是位于 Fork/Join 框架下方的线程池。
private static Executor pool = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() );
private static int[][] sumParallel( int[][] a, int[][] b ) throws InterruptedException {
int[][] result = createGrid(a.length);
CountDownLatch latch = new CountDownLatch(a.length);
for ( int i=0; i<a.length; i++ ) {
pool.execute( new SumTask(latch, a,b,i, result) );
}
latch.await();
return result;
}
public static class SumTask implements Runnable {
private CountDownLatch latch;
private int[][] a;
private int[][] b;
private int row;
private int[][] result;
public SumTask(CountDownLatch latch, int[][] a, int[][] b, int row, int[][] result) {
this.latch = latch;
this.a = a;
this.b = b;
this.row = row;
this.result = result;
}
public void run() {
for ( int y=0; y<a.length; y++ ) {
result[row][y] = a[row][y] + b[row][y];
}
latch.countDown();
}
}
为了更有趣,这里有一个 ForkJoin 等效项:
public class Sum2DFJ {
public static void main( String[] args ) throws ExecutionException, InterruptedException {
int[][] data = {{1,2,3},{1,2,3},{1,2,3}};
SumTask task = new SumTask(data, data);
ForkJoinPool pool = new ForkJoinPool();
pool.execute(task);
int[][] result = task.get();
for ( int x=0; x<data.length; x++ ) {
for ( int y=0; y<data.length; y++ ) {
System.out.println("result[x][y] = " + result[x][y]);
}
}
}
}
@SuppressWarnings("unchecked")
class SumTask extends RecursiveTask<int[][]> {
private int[][] a;
private int[][] b;
public SumTask( int[][] a, int[][] b ) {
this.a = a;
this.b = b;
}
protected int[][] compute() {
int[][] result = createGrid(a.length);
List<ForkJoinTask> children = new ArrayList();
for ( int i=0; i<a.length; i++ ) {
children.add( new SumChildTask(a,b,i, result) );
}
invokeAll(children);
return result;
}
private static int[][] createGrid(int size) {
int[][] data = new int[size][size];
for ( int x=0; x<size; x++ ) {
for ( int y=0; y<size; y++ ) {
data[x][y] = 0;
}
}
return data;
}
}
class SumChildTask extends RecursiveAction {
private int[][] a;
private int[][] b;
private int row;
private int[][] result;
public SumChildTask(int[][] a, int[][] b, int row, int[][] result) {
this.a = a;
this.b = b;
this.row = row;
this.result = result;
}
protected void compute() {
for ( int i=0; i<b.length; i++ ) {
result[row][i] = a[row][i] + b[row][i];
}
}
}
关于java - 并行对两个数组的每个元素求和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24485708/
这个问题在这里已经有了答案: Prolog - count repetitions in list (3 个答案) 关闭 7 年前。 所以我正在尝试创建一种方法来确定列表中 N 的数量。我已经试验了
使用 sscanf 或任何其他命令从分号后的文件读取的最佳方法是什么,例如,如果我的文件有 5: 4 5 6 7。如何将冒号后的值存储在数组中。此外,分号后面的整数数量可能会有所不同,即在上面给出的示
我正在尝试返回第 n 个数字。如果数字是 3 或 7 的倍数,则从 1 开始,则跳过该数字并获取下一个数字。但是,如果数字是 3 和 7 的倍数,则不会跳过该数字。 public int Multip
如何有效地从末尾获取一定数量的元素? 1 looks like 2 three!! 例如,如何获取最后 2 个 div 的内容? 最佳答案 $(document).ready(function(){
//Generate Food Personality for(i=0; i
我试图在给定的排序数组中找到最大的 K 个数。 例如:输入 -> [ 5, 12, 45, 32, 9, 20, 15]输出 -> K = 3, [45, 32, 20] 到目前为止我编写的代码返回最
两个数字表 a 和 b 被写入并按升序合并在一起,并删除重复项。现在的问题是在这个 super 表中找到比 O(n) 复杂度更好的 nth 数。 Limits 1 #include using nam
给定一个包含 N 个元素的数组 A,我需要找到对 (i,j) 使得 i 不等于 j 并且如果我们为所有对 (i, j) 然后它来到第k个位置。 示例:让 N=4 和数组 A=[1 2 3 4] 如果
给定一组跳过的数字,我需要找到该组中不存在的第 N 个数字。示例: 给定一组 [1, 4, 5] 一些结果: 对于 N = 1 结果 0 对于 N = 2 结果 2(因为 1 被跳过) 对于 N =
几个月前在亚马逊的招聘挑战中遇到了这个问题。 给定两个数字 a 和 b 及其倍数的升序列表,找出第 n 个倍数。 例如,如果 a = 4 , b = 6 和 n = 6 那么答案是 18因为列表是 4
所以我最近一直在研究 Python,我试图找到一种方法来在单个表达式中输出斐波那契数列的第 n 个数。这是我到目前为止编写的代码: (lambda f: f if f 1 # n == 2 -> 1
作业是编写一个 C++ 程序,它接受输入数字 n 并输出序列中的第 n 个数字: 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6 ... 这是我到目前为止想出的:
问题很简单(答案很可能):如何找到数组中最小的 2 个数字? for ( i = 1; i 关于c++ - 数组中最小的 2 个数,我们在Stack Overflow上找到一个类似的问题: ht
您可以调用Nokogiri::XML::Node#ancestors.size 来查看节点的嵌套深度。但是有没有办法确定嵌套最深的子节点的嵌套深度呢? 或者,您如何找到从一个节点下降的所有叶节点? 最
这个任务是找到n个数字的fibanocci。任务: 1.找出n个数的斐波那契数。 2.使用变量n,first=0,second=1,next,c。输入格式:使用 printf 语句。使用 scanf
我想添加每 10 个元素的数量。 例如, function myFunction() { for (var i = 1; i "; } } 输出: 1,2,3,4,5,6,7,8,9,
我想编写一个程序来计算斐波那契数列的第 n 个数,这是我使用 printf 和 scanf 完成的。但我希望更改我的程序,以便在命令行中输入序列号,而不是在程序提示时输入。这就是我想出的。它可以编译,
我有一个方案中的对象列表。每个对象都与一个可以在运行时计算的置信度值相关联。我想找到具有最高置信度值的前 50 个此类对象。示例:((WordPair1) (WordPair2)) 等等都是我的对象。
我正在寻找一种给定目标的算法,返回目标位为 0 的第 N 个数字。 例如,对于n={0,1,2,3}和target=1的输入,输出将是(二进制) 000,001,100,101 最佳答案 只写值N-1
我正在尝试创建一个函数来获取 vector 中的 3 个最大数字。例如:数字:1 6 2 5 3 7 4结果:5 6 7 我想我可以对它们进行 DESC 排序,在开始时获取 3 个数字,然后再对它们进
我是一名优秀的程序员,十分优秀!