【问题标题】:Parallel image renaming in Java with ExecutorService: Doesn't use 100% of my cpu-power使用 ExecutorService 在 Java 中进行并行图像重命名:不使用 100% 的 cpu-power
【发布时间】:2013-03-01 15:31:14
【问题描述】:

我的并行 Java 代码有问题。我尝试从磁盘读取一些图像,更改图像的名称,然后将它们再次保存到不同的文件夹中。 为此,我尝试按如下方式并行运行它:

    int nrOfThreads = Runtime.getRuntime().availableProcessors();
    int nrOfImagesPerThread = Math.round(remainingImages.size()/((float)nrOfThreads));

    ExecutorService ex2 = Executors.newFixedThreadPool(nrOfThreads);
    int indexCounter = 0; 
    for(int i = 0; i<  nrOfThreads; ++i) {
        if(i != (nrOfThreads-1)) {
            ex2.execute(new ImageProcessing(remainingImages.subList(indexCounter, indexCounter+nrOfImagesPerThread), newNames.subList(indexCounter,indexCounter+nrOfImagesPerThread))); 
            indexCounter+=nrOfImagesPerThread;
        }else {
            ex2.execute(new ImageProcessing(remainingImages.subList(indexCounter, remainingImages.size()), newNames.subList(indexCounter,remainingImages.size()))); 
        } 
    }


    ex2.shutdown();

    try {
        ex2.awaitTermination(12, TimeUnit.HOURS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

这是 ImageProcessing 类:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;

public class ImageProcessing implements Runnable {

private List<String> oldPaths;
private List<String> newPaths;

public ImageProcessing(List<String> oldPaths, List<String> newPaths) {
    this.oldPaths = oldPaths;
    this.newPaths = newPaths;
}

@Override
public void run() { 
    for(int i = 0; i<  oldPaths.size();++i) {
        try {
            BufferedImage img = ImageIO.read(new File(oldPaths.get(i)));
            File output = new File(newPaths.get(i)); 
            ImageIO.write(img, "jpg", output);
        } catch (IOException e) { 
            e.printStackTrace();
        }
    }
}

}

我将 for 循环中的图像位置划分为(线程数)部分,因此在我的情况下大约 8 个部分。当我现在运行代码时,它确实是并行运行的,但它并没有利用我 100% 的 cpu 功率。它只使用了每个处理器的 25% 左右。

有人知道为什么会这样吗?还是我只是在编程的某个地方搞砸了?

非常感谢!

编辑:为了让寻找相同功能的人完成,我查看了 Apache 公共库 (see here),发现了一种从一个硬盘到另一个。 ImageProcessing 类现在如下所示:

import java.io.File;
import java.io.IOException;
import java.util.List;


import org.apache.commons.io.FileUtils;


public class ImageProcessing implements Runnable {

private List<String> oldPaths;
private List<String> newPaths;

public ImageProcessing(List<String> oldPaths, List<String> newPaths) {
    this.oldPaths = oldPaths;
    this.newPaths = newPaths;
}

@Override
public void run() { 
    for(int i = 0; i<  oldPaths.size();++i) {
        File sourceFile = new File(oldPaths.get(i)); 

        File targetFile = new File(newPaths.get(i)); 
        //copy file from one location to other
        try {
            FileUtils.copyFile(sourceFile, targetFile);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
}

【问题讨论】:

  • 我认为这不是 CPU,而是 I/O 绑定操作。这永远不会使用 100% 的 CPU,尤其是在那种马力的情况下……顺便说一下,你为什么要使用 ImageIO 呢?由于您不进行任何处理,只是文件 IO,因此您可以使用通用(更快)的方法来处理文件...
  • 确实,我没有考虑过。图像来自使用一些 USB 2.0 的外部高清...可能不是转换它们的最快方法...非常感谢!我会看看文件 IO。
  • 嗯,USB 2.0 并不是最快的。我认为您不需要它是多线程的,我要么等到它完成,要么找到一种方法将磁盘直接用作 SATA 设备......这可能会对速度产生巨大影响
  • 谢谢,通常我会在我的 SSD 上运行它,但因为它大约 1 TB 的图像 SSD 并不是一个真正的选择。因为我在我的笔记本电脑上运行它,我可能需要给我找一台内部 HD 更大的电脑……或者我只是等到它完成……但我很高兴这不仅仅是因为我的编程风格因为这在过去的 3 个小时里让我很烦;)
  • 使用USB2.0,无论CPU如何,您都可以预期1/2天的读/写时间:)

标签: java multithreading parallel-processing executor


【解决方案1】:

您的问题是,这里的瓶颈肯定是磁盘的 I/O。 您可能需要在没有 ExecutorService 的情况下同时重命名文件。

换句话说:将更改(重命名文件)写入磁盘所消耗的时间比 CPU 使用的时间要多。

你不能多线程这样的动作。

只需测量代码的串行(非多线程)版本所需的时间,并将其与多线程代码所需的时间进行比较。它或多或少是一样的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多