java - 并行化此Java代码的最佳方法

标签 java multithreading parallel-processing

我将如何在Java中使用Threads并行处理这段代码?它从图像中提取所有轮廓,并仅使用图像轮廓创建新图像。


import java.io.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.awt.Color;

public class Contornos {

static int h, w;

static float debugTime;

public static void main(String[] args) {
    try {

        File fichImagen = new File("test.jpg");

        BufferedImage image = ImageIO.read(fichImagen);

        w = image.getWidth();
        h = image.getHeight();

        int[] inicial = new int[w * h];

        int[] resultadoR = new int[w * h];
        int[] resultadoG = new int[w * h];
        int[] resultadoB = new int[w * h];

        int[][] procesarR = new int[h][w];
        int[][] procesarG = new int[h][w];
        int[][] procesarB = new int[h][w];

        int[][] procesarBN = new int[h][w];

        int[][] binaria = new int[h][w];

        int[] resultado = new int[w * h];

        image.getRGB(0, 0, w, h, inicial, 0, w);

        for (int i = 0; i < w * h; i++) {
            Color c = new Color(inicial[i]);
            resultadoR[i] = c.getRed();
            resultadoG[i] = c.getGreen();
            resultadoB[i] = c.getBlue();
        }

        int k = 0;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                procesarR[i][j] = resultadoR[k];
                procesarG[i][j] = resultadoG[k];
                procesarB[i][j] = resultadoB[k];
                k++;
            }
        }

        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

                procesarBN[i][j] = (int) (0.2989 * procesarR[i][j] + 0.5870 * procesarG[i][j] + 0.1140 * procesarB[i][j]);

            }
        }


        binaria = extraerContornos(procesarBN);

        k = 0;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                resultado[k++] = binaria[i][j];
            }
        }

        image.setRGB(0, 0, w, h, resultado, 0, w);
        ImageIO.write(image, "JPG", new File("allJPG.jpg"));

    } catch (IOException e) {
    }

}

static void debugStart() {
    debugTime = System.nanoTime();
}

static void debugEnd() {
    float elapsedTime = System.nanoTime()-debugTime;

    System.out.println( (elapsedTime/1000000) + " ms ");  
}

private static int[][] extraerContornos(int[][] matriz) {
    int modx, mody;

    int[][] sobelx = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    int[][] sobely = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};

    int[][] modg = new int[h][w];
    double[][] theta = new double[h][w];
    int[][] thetanor = new int[h][w];
    int[][] contorno = new int[h][w];

    int umbral = 10;
    int superan = 0, ncontorno = 0;
    double t;
    int signo;
    int uno, dos;

    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (i == 0 || i == h - 1 || j == 0 || j == w - 1) {
                modg[i][j] = 0;
                theta[i][j] = 0.0;
                thetanor[i][j] = 0;
            } else {
                modx = 0;
                mody = 0;
                for (int k = -1; k <= 1; k++) {
                    for (int l = -1; l <= 1; l++) {
                        modx += matriz[i + k][j + l] * sobelx[k + 1][l + 1];
                        mody += matriz[i + k][j + l] * sobely[k + 1][l + 1];
                    }
                }
                modx = modx / 4;
                mody = mody / 4;

                modg[i][j] = (int) Math.sqrt(modx * modx + mody * mody);

                theta[i][j] = Math.atan2(mody, modx);
                thetanor[i][j] = (int) (theta[i][j] * 256.0 / (2.0 * Math.PI));
            }
        }
    }

    for (int i = 1; i < h - 1; i++) {
        for (int j = 1; j < w - 1; j++) {
            contorno[i][j] = 0;
            if (modg[i][j] >= umbral) {
                superan++;
                t = Math.tan(theta[i][j]);
                if (t >= 0.0) {
                    signo = 1;
                } else {
                    signo = -1;
                }
                if (Math.abs(t) < 1.0) {
                    uno = interpolar(modg[i][j + 1], modg[i - signo][j + 1], t);
                    dos = interpolar(modg[i][j - 1], modg[i + signo][j - 1], t);
                } else {
                    t = 1 / t;
                    uno = interpolar(modg[i - 1][j], modg[i - 1][j + signo], t);
                    dos = interpolar(modg[i + 1][j], modg[i + 1][j - signo], t);
                }
                if (modg[i][j] > uno && modg[i][j] >= dos) {
                    ncontorno++;
                    contorno[i][j] = 255;
                }
            }
        }
    }

    debugEnd();

    return contorno;

}

private static int interpolar(int valor1, int valor2, double tangente) {
    return (int) (valor1 + (valor2 - valor1) * Math.abs(tangente));
}
}


我相信我可以在extraerContornos方法(用于for循环)中使用Threads,并在最后使用join()以获得结果,但这只是我的猜测。

这是并行化此方法的正确方法吗?关于如何知道何时何地应该开始并行化任何代码的一般提示?

最佳答案

有关如何何时何地开始并行化任何代码的一般提示?

好吧,在没有定量支持的证据的情况下,永远不要开始并行处理任何代码,因为这将提高系统性能。

永远不能,
即使有院士或想咨询的大师告诉您也这样做。

首先,收集大量证据,证明它完全没有意义,并且这样的代码再造将为原始的纯[SERIAL]代码执行流程带来多大的积极影响。

就像是自然界或商业界一样-谁会为获得相同的结果付出一分钱呢?

谁将以当前的薪水支付X- [man * hours]的工作时间,以仅获得绩效的第一个1.01倍的提高(更不用说想成为平行职业的帮派了,因为他们的表现甚至比原始表现还差... -在增加间接费用的隐藏费用之前见过)-谁愿意为此付费?



如何开始分析可能带来的利益与负面影响?

首先,尝试了解“力学”,如何由[O / S内核,编程语言,用户程序]组成的分层复合系统使用“ just”-或true- [CONCURRENT]进程调度。

在不知道这一点的情况下,人们永远无法量化条目的实际成本,有时人们甚至不知不觉地支付了所有此类成本,即所得到的处理流程甚至从未至少是“公正的”-[PARALLEL]处理(如果有人忘了理解python GIL锁定的中央“并发阻止-独占锁定”阻止,这很可能会帮助掩盖某些I / O延迟,但实际上并没有任何形式的改进CPU限制的处理性能,但是所有人都必须付出产生进程执行环境+ python-internal-state的完整副本的所有巨大费用-所有这些最终都没有得到任何回报。如果在天真的尝试“平行化”行动主义之前缺乏知识或缺少知识,事情就可能会过去。

好的,一旦您对可用于生成线程和进程的操作系统“机制”感到满意,就可以估算或更好地确定这样做的成本(开始量化工作),知道一个人需要支付多少[ns]生成第一个,第二个,第...,第三十个子线程或单独的O / S进程,或者使用一些高级语言构造函数(扇出一群线程/进程)进行分配的附加成本是多少大量的工作,最后将结果收集回原始请求者(仅使用[CONCURRENT].map(...){...}等人的高级语法,这些语法在其下端执行所有隐藏在视线之外的脏工作用户程序设计师(不是讲“正义”编码器)的人,他们甚至不花零努力来完全负责地理解其“正义”编码的“机械” +“经济”成本工作))。

在不知道.foreach(...){...}的实际成本的情况下(为了清晰简洁起见,在技术上并未进行描述),对于任何人来说,尝试阅读并尝试全面了解其代码设计上下文

付完一个以上的钱很容易...

有关此风险的更多详细信息,请检查in Fig.1, that are principally always present, being detailed and discussed in the trailer sections

返回您的代码:

Sobel过滤器内核引入了(naive-)-thread-mapping的非本地依赖关系,最好从一个简单的部分开始,在该部分中,绝对独立性是直接可见的:

可以节省所有重复的[ns] -constructor开销并提高性能:

    for (     int i = 0; i < h; i++ ) {
        for ( int j = 0; j < w; j++ ) {

            Color c = new Color( inicial[i * w + j] );

            procesarBN[i][j] = (int) ( 0.2989 * c.getRed()
                                     + 0.5870 * c.getGreen()
                                     + 0.1140 * c.getBlue()
                                       );
        }
    }


代替这些for(){...} -s:

    for (int i = 0; i < w * h; i++) {
        Color c = new Color(inicial[i]);
        resultadoR[i] = c.getRed();
        resultadoG[i] = c.getGreen();
        resultadoB[i] = c.getBlue();
    }

    int k = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            procesarR[i][j] = resultadoR[k];
            procesarG[i][j] = resultadoG[k];
            procesarB[i][j] = resultadoB[k];
            k++;
        }
    }

    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {

            procesarBN[i][j] = (int) (0.2989 * procesarR[i][j] + 0.5870 * procesarG[i][j] + 0.1140 * procesarB[i][j]);

        }
    }


效果如何?

在阿姆达尔定律的triple-for(){...}部分中:


零附加成本净额:改进/消除了[SERIAL]-构造函数循环开销的2/3
以零净附加成本支付:改进/取消了for(){...} -memIO(即,不支付〜h * w * 1.320+ [us]每个!!!)
零附加成本净额:改进/消除了( 4 * h * w * 3 ) -memALLOC,再次节省了( 4 * h * w * 3 * 4 )[TIME]复杂度ZOO分类法的多项式规模域中的大量资源。


并且在[SPACE]处理中运行它们也可能会感到安全,因为此处的像素值处理原则上是独立的(但不是在Sobel中,不是在轮廓检测器算法中)。

所以在这里,
如果[CONCURRENT][CONCURRENT]进程调度,可能会有所帮助


以一些非零的附加成本,该处理将利用多个计算资源(超过1个CPU内核,该CPU内核在原始的纯[PARALLEL]代码执行中运行),因此可以安全地进行像素处理-网格映射到此类(可用资源支持的)线程池或其他代码处理工具。


然而,
只有且仅当所有流程分配/取消分配等附加成本的总和至少由增加的[SERIAL]处理数量来证明是合理的时,任何非[SERIAL]的尝试才有意义。

比收货多付钱绝对不是明智之举。

因此,在确定可能对生产代码产生正面影响之前,先确定基准,基准和基准。

始终尝试在pure- [CONCURRENT]部分中进行改进,因为它们具有零附加成本,但可能会减少总体处理时间。

Q.E.D.以上。

关于java - 并行化此Java代码的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47464029/

相关文章:

java - 并行从 Windows 共享目录读取文件

并行运行多个php脚本的PHP脚本

java - `hashCode` 的默认实现是什么?

java - 为什么我会得到在静态和实例初始化 block 中分配的静态变量的输出?

Java Nashorn JSObject 将函数设置为成员

swift - 如何在 Swift 中设置实时线程?

java - 有人可以澄清与完整初始化相关的 Java 内存模型最终字段语义吗?

java - 有没有办法在< 21 API上实现计划任务?

ios - NSOperationQueue 泄漏?

使用execl从txt中收集数据