如何在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 for循环)中使用Threads,在最后使用join()
来获取结果,但这只是我的猜测。
这是一种正确的并行化方法吗?关于如何知道何时何地开始并行化任何代码的一般提示?
答案 0 :(得分:2)
嗯,从未开始并行化任何代码,如果没有定量支持的证据,它将提高系统性能。
永远不会,
即使有任何院士或崇拜大师告诉你这样做。
首先收集相当数量的证据,它具有任何感觉,并且这样的代码重新设计带来的积极优势将超过原始的纯粹 [SERIAL]
,代码执行流程。
就像在自然界中或在商业中一样 - 谁会为获得相同的结果多付一分钱?
谁将以目前的工资率支付X- [man * hours]工作,以获得性能上的第一个1.01x改进(不是说想要提供甚至比原始性能更差的想要平行的帮派...因为在加载开销的隐藏成本之前没见过 - 谁会为此付钱?
首先,尝试理解&#34;机制&#34;,如何分层复合系统 - 由[O / S内核,编程语言,用户程序组成] ] - 使用&#34;只需&#34; - [CONCURRENT]
或true- [PARALLEL]
进程安排来协调前进。 / p>
在不知道这一点的情况下,人们永远无法量化进入的实际成本,有时人们甚至在没有意识到的情况下支付所有这些成本,结果处理流程从来没有至少是#34;只是&#34; ; - [CONCURRENT]
处理(如果忘记理解中心&#34;并发防止独占锁定&#34;阻止python GIL锁定,这可能有助于掩盖某些类型的I / O延迟,但从来没有任何改进的CPU绑定处理性能,但所有必须支付产生流程执行的完整副本 - 环境+ python-internal-state的所有巨大成本 - 所有这一切都是为了在最后得到任何东西。没有。是的,如果事情变得糟糕或缺失,那么可能事情就会变得糟糕,以及“并行化”和“行动主义”。
好的,一旦你对操作系统感觉很舒服,那么#mechan;&34;可用于产生线程和流程,您可以猜测或更好地衡量这样做的成本 - 开始定量工作 - 知道需要支付多少[ns] 来产生第一个,第二个,... thirtyninth子线程或单独的操作系统进程,或者使用某些更高级别的语言构造函数的附加成本,即扇出一大堆线程/进程,分发一些工作量,最后将大量结果收集回原始请求者(仅使用.map(...){...}
,.foreach(...){...}
等人的高级语法,这些语法在其下端完成了所有看不见的脏工作。用户程序设计师(不是说&#34;只是&#34; - 编码人员,他们甚至不会花费任何努力来完全负责地理解&#34;机制&#34; +&#34;经济&#34;他们&#34;正常&#34;编码的工作))。
不知道[ns]
中的实际费用(技术上没有为了清晰和简洁in Fig.1, that are principally always present, being detailed and discussed in the trailer sections而描述),任何人尝试阅读和尝试几乎都没有意义全面了解其代码设计背景the criticism of the Amdahl's Law
返回您的代码:
Sobel-filter内核引入(naive - ) - 线程映射非本地依赖关系,最好从一个简单的部分开始,其中绝对独立性是直接可见的:
可以保存所有重复的for(){...}
- 构造函数开销并提高性能:
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()
);
}
}
而不是这些triple-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]);
}
}
在Amdahl法律的 [SERIAL]
部分:
for(){...}
- 构造函数循环开销成本的2/3 ( 4 * h * w * 3 )
- memIO (即不支付~h * w * 1.320+ [我们]每个!!!)( 4 * h * w * 3 * 4 )
- memALLOCs ,再次在[TIME]
中节省了大量资源和[SPACE]
,复杂性ZOO分类法的多项式缩放域。并且在 [CONCURRENT]
处理中运行这些也感觉很安全,因为这个像素值处理在这里主要是独立的(但不在Sobel中,而不在轮廓检测器中)算法)。
所以,在这里,
任何 [CONCURRENT]
或 [PARALLEL]
流程安排可能有所帮助,如果
[SERIAL]
,代码执行,将安全地像素网格映射到这样的(可用资源支持的)线程池或其他代码处理工具上。然而,
任何非 [SERIAL]
的尝试都是有道理的,当且仅当所有流程分配/解除分配等附加成本的块状物至少得到通过增加 [CONCURRENT]
处理的计算量来证明这一点。
因此,基准,基准和基准,然后才能决定什么可能对生产代码产生积极影响。
始终尝试在纯 [SERIAL]
部分进行改进,因为这些部分具有零附加成本,但可能会缩短整体处理时间。
Q.E.D。上方。