大量の画像ファイルを解析するための小さなJavaアプリケーションを作成しています。今のところ、画像内のすべてのピクセルの明るさを平均し、それをフォルダ内の他の画像と比較することによって、フォルダ内の最も明るい画像を見つけます。起動後にJavaプログラムのパフォーマンスが大幅に低下するのはなぜですか?
時々、スタートアップ直後に100+画像/秒のレートが得られますが、これはほとんど常に<20画像/秒に低下します。なぜそうはわかりません。 100+ images/secの場合、CPU使用率は100%ですが、それは20%程度に低下しますが、これは低すぎるようです。ここで
は、メインクラスです:
public class ImageAnalysis {
public static final ConcurrentLinkedQueue<File> queue = new ConcurrentLinkedQueue<>();
private static final ConcurrentLinkedQueue<ImageResult> results = new ConcurrentLinkedQueue<>();
private static int size;
private static AtomicInteger running = new AtomicInteger();
private static AtomicInteger completed = new AtomicInteger();
private static long lastPrint = 0;
private static int completedAtLastPrint;
public static void main(String[] args){
File rio = new File(IO.CAPTURES_DIRECTORY.getAbsolutePath() + File.separator + "Rio de Janeiro");
String month = "12";
Collections.addAll(queue, rio.listFiles((dir, name) -> {
return (name.substring(0, 2).equals(month));
}));
size = queue.size();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
for (int i = 0; i < 8; i++){
AnalysisThread t = new AnalysisThread();
t.setPriority(Thread.MAX_PRIORITY);
executor.execute(t);
running.incrementAndGet();
}
}
public synchronized static void finished(){
if (running.decrementAndGet() <= 0){
ImageResult max = new ImageResult(null, 0);
for (ImageResult r : results){
if (r.averageBrightness > max.averageBrightness){
max = r;
}
}
System.out.println("Max Red: " + max.averageBrightness + " File: " + max.file.getAbsolutePath());
}
}
public synchronized static void finishedImage(ImageResult result){
results.add(result);
int c = completed.incrementAndGet();
if (System.currentTimeMillis() - lastPrint > 10000){
System.out.println("Completed: " + c + "/" + size + " = " + ((double) c/(double) size) * 100 + "%");
System.out.println("Rate: " + ((double) c - (double) completedAtLastPrint)/10D + " images/sec");
completedAtLastPrint = c;
lastPrint = System.currentTimeMillis();
}
}
}
とスレッドクラス:
public class AnalysisThread extends Thread {
@Override
public void run() {
while(!ImageAnalysis.queue.isEmpty()) {
File f = ImageAnalysis.queue.poll();
BufferedImage image;
try {
image = ImageIO.read(f);
double color = 0;
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
//Color c = new Color(image.getRGB(x, y));
color += image.getRGB(x,y);
}
}
color /= (image.getWidth() * image.getHeight());
ImageAnalysis.finishedImage((new ImageResult(f, color)));
} catch (IOException e) {
e.printStackTrace();
}
}
ImageAnalysis.finished();
}
}
jvisualvmなどのプロファイラでアプリケーションを実行し、サンプラを使用して、どのメソッドが最も時間を要するかを測定できます。また、1つのスレッドで実行し、違いを観察してみてください。特定の操作でスレッドが互いにブロックしている可能性があります。 –
あなたのクラスは 'Thread 'を拡張しています。優先度を設定していますが、' Executor'で実行しています。 'Runnable 'として扱うだけです。優先度に影響を与えたい場合は、 'ThreadFactory.'を定義する必要があります。それ以外の場合、クラスはRunnableを実装するだけです。 – EJP
あなたは試みましたか: 'ImageIO.setUseCache(false);'? – user3707125