我有一个程序处理很多文件,其中每个文件需要完成两件事:首先,读取并处理文件的某些部分,然后生成结果MyFileData
被存储。第一部分可以并行,第二部分则不能。
按顺序执行所有操作非常慢,因为 CPU 必须等待磁盘,然后它会工作一点,然后发出另一个请求,然后再次等待......
我做了以下事情
class MyCallable implements Callable<MyFileData> {
MyCallable(File file) {
this.file = file;
}
public MyFileData call() {
return someSlowOperation(file);
}
private final File file;
}
for (File f : files) futures.add(executorService.submit(new MyCallable(f)));
for (Future<MyFileData> f : futures) sequentialOperation(f.get());
这很有帮助。不过,我想改进两件事:
The sequentialOperation
以固定顺序执行,而不是先处理任何可用的结果。我怎样才能改变它?
有数千个文件需要处理,启动数千个磁盘请求可能会导致磁盘垃圾。通过使用Executors.newFixedThreadPool(10)
我限制了这个数字,但我正在寻找更好的东西。理想情况下,它应该是自调整的,以便它在不同的计算机上以最佳方式工作(例如,在以下情况下发出更多请求)RAID and/or NCQ是否可用等)。我不认为它可以基于找出硬件配置,但测量处理速度并基于它进行优化应该somehow有可能。任何想法?
equentialOperation 以固定顺序执行,而不是先处理任何可用的结果。我怎样才能改变它?
这正是竣工服务作用:它并行处理任务并在完成后返回它们,无论提交顺序如何。
简化(未测试)示例:
int NUM_THREADS = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
CompletionService<MyFileData> completionService = new ExecutorCompletionService<MyFileData>(executor);
for (File f : files) futures.add(completionService.submit(new MyCallable(f)));
for(int i = 0; i < futures.size(); i++) {
Future<MyFileData> next = completionService.take();
sequentialOperation(next.get());
}
有数千个文件需要处理,启动数千个磁盘请求可能会导致磁盘垃圾。通过使用 Executors.newFixedThreadPool(10) 我限制了这个数字,但是我正在寻找更好的东西。
我对此不是 100% 确定。我想这取决于你有多少个磁盘,但我认为磁盘访问部分不应该分成太多线程(每个磁盘一个线程可能是明智的):如果许多线程同时访问一个磁盘,它会花更多的时间去寻找而不是阅读。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)