使用线程并发地散列(sha1)多个文件

时间:2011-11-05 12:33:04

标签: java multithreading sha1 java-7

我有N个大文件(不少于250M)来散列。这些文件位于P物理驱动器上。

我想与最大K个活动线程同时散列它们但是我不能散列超过每个物理驱动器的M个文件,因为它会减慢整个过程(我运行测试,解析61个文件,并使用8个线程)比1个线程慢;文件几乎都在同一个磁盘上。

我想知道最好的方法是什么:

  • 我可以使用Executors.newFixedThreadPool(K)
  • 然后我会使用计数器提交任务,以确定是否应该添加新任务。

我的代码是:

int K = 8;
int M = 1;
Queue<Path> queue = null; // get the files to hash
final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(K);
final ConcurrentMap<FileStore, Integer> counter = new ConcurrentHashMap<>();
final ConcurrentMap<FileStore, Integer> maxCounter = new ConcurrentHashMap<>();
for (FileStore store : FileSystems.getDefault().getFileStores()) {
  counter.put(store, 0);
  maxCounter.put(store, M);
}
List<Future<Result>> result = new ArrayList<>();
while (!queue.isEmpty()) {
  final Path current = queue.poll();
  final FileStore store = Files.getFileStore(current);
  if (counter.get(store) < maxCounter.get(store)) {
    result.add(newFixedThreadPool.submit(new Callable<Result>() {

      @Override
      public Entry<Path, String> call() throws Exception {
        counter.put(store, counter.get(store) + 1);
        String hash = null; // Hash the file
        counter.put(store, counter.get(store) - 1);
        return new Result(path, hash);
      }

    }));
  } else queue.offer(current);
}

抛开潜在的非线程安全操作(比如我如何使用计数器),是否有更好的方法来实现我的目标?

我也认为这里的循环可能有点太多,因为它可能会占用很多进程(几乎就像一个无限循环)。

2 个答案:

答案 0 :(得分:0)

如果驱动硬件配置在编译时是未知的,并且可能是chaged / upgrade,那么每个驱动器使用一个线程池并使用户可配置的线程计数很诱人。我不熟悉'newFixedThreadPool' - 线程数是否可以在运行时更改以优化性能?

答案 1 :(得分:0)

经过很长时间,我找到了一个解决方案来满足我的需求:我使用AtomicInteger和每个提交的任务,而不是整数计数器,或ExecutorService或其他任何东西。在一个驱动器的每个文件中共享Semaphore

像:

ConcurrentMap<FileStore, Semaphore> map = new ConcurrentHashMap<>();
ExecutorService es = Executors.newFixedThreadPool(10);
for (Path path : listFile()) {
  final FileStore store = Files.getFileStore(path);
  final Semaphore semaphore = map.computeIfAbsent(store, key -> new Semaphore(getAllocatedCredits(store)));
  final int cost = computeCost(path);
  es.submit(() -> {
    semaphore.acquire(cost);
    try {
      ... some work ...
    } finally {
      semaphore.release(cost);
    }
  });
}


int getAllocatedCredits(FileStore store) {return 2;}
int computeCost(Path path) {return 1;}

请注意Java 8的帮助,尤其是computeIfAbsentsubmit