因此,我试图从磁盘中删除listDir中列出的n个文件,从而将listDir分为4部分,并使其从磁盘中并行删除。这里的目的是并行执行此操作,以使其快速而不是顺序进行。 deleteObject(x,credential,token)可以假定为一个API,该API最终从磁盘上删除了一个对象,并且是一个原子操作。成功删除后返回true,否则返回false
我在这里有几个问题
如果ExecutorService的操作之一返回false,则整个deleteMain()API都将返回false
private boolean deleteMain(String parent, List<Structure>
listDir, String place, String node, Sequence<String>
groups, String Uid) throws IOException {
int noCores = Runtime.getRuntime().availableProcessors();
List<List<Integer>> splittedList = splitList(listDir, noCores);
System.out.println(splittedList.size());
System.out.println("NoOfCores" + noCores);
Set<Callable<Boolean>> callables = new HashSet<Callable<Boolean>>();
for (int i = 0; i < splittedList.size(); i++) {
List<Integer> l = splittedList.get(i);
callables.add(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return parallelDeleteOperation(parent, listDir, place, node, groups Uid);
}
});
}
ExecutorService service = Executors.newFixedThreadPool(noCores);
try {
List<Future<Boolean>> futures = service.invokeAll(callables);
for (Future<Boolean> future : futures) {
if (future.get() != true)
return future.get();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
service.shutdown();
return true;
}
private Boolean parallelDeleteOperation(String parent, List<Structure>
listDir, String place, String node, Sequence<String>
groups, String Uid) throws IOException {
for (int i = 0; i < listDir.size(); i++) {
final String name = listDir.get(i).filename;
final String filePath = "/" + (parent.isEmpty() ? "" : (parent +
"/")) + name;
final DeleteMessage message = new DeleteMessage(name, place, node
filePath);
final boolean Status = delete(message, groups, Uid, place);
if (Status != true)
return Status;
}
return true;
}
答案 0 :(得分:1)
- 所以我有4个并行方法,虽然我通过invokeAll来执行,并且Executors声明了4个线程。newFixedThreadPool(4)会总是有1个线程分配给1个方法?
通常,如果任务数量等于池中的线程是正确的,但不能保证。这在很大程度上取决于池中的任务。
Executors.newFixedThreadPool(4).invokeAll(IntStream.range(0, 8).mapToObj(i -> (Callable<Integer>) () -> {
System.out.println(Thread.currentThread().getName() + ": " + i);
return 0;
}).collect(Collectors.toList()));
如果池中有更多任务(如上所述),则输出如下。没有明显的可预测规则来处理任务:
pool-1-thread-1: 0
pool-1-thread-2: 1
pool-1-thread-3: 2
pool-1-thread-1: 4
pool-1-thread-1: 5
pool-1-thread-1: 6
pool-1-thread-1: 7
pool-1-thread-4: 3
- 我是否需要在parallelDeleteOperation()方法的for循环中对迭代器“ i”进行同步并使用volatile。
不,您不需要。您已经将原始列表拆分为单独的四个列表。
在您的代码中:
最终列表listDir1 = listDir.subList(0,listDir.size()/ 4);
关于您的第3个问题:
- 将list分成4个部分并执行它,而不是让多个线程在一个很大的list上执行delete操作,有什么好处。
您最好在实际条件下进行一些测试。太复杂了,不能说是好还是不好。
当您删除大列表上的 时,竞争条件可能比预先拆分列表更为严重,这可能会增加额外的开销。
此外,即使没有任何并行性,其性能也可能不错。当涉及到多用户系统时,由于线程上下文切换的开销,并行化版本甚至可能比顺序版本差。
您必须对其进行测试,并且测试助手代码可以为:
Long start = 0L;
List<Long> list = new ArrayList<>();
for (int i = 0; i < 1_000; ++i) {
start = System.nanoTime();
// your method to be tested;
list.add(System.nanoTime() - start);
}
System.out.println("Time cost summary: " + list.stream().collect(Collectors.summarizingLong(Long::valueOf)));
- 如果ExecutorService的操作之一返回false,则整个deleteMain()API都将返回false
我想重构您的代码,以使其更简洁并满足您的最后要求(第4条):
// using the core as the count;
// since your task is CPU-bound, we can directly use parallelStream;
private static void testThreadPool(List<Integer> listDir) {
// if one of the tasks failed, you got isFailed == true;
boolean isFailed = splitList(listDir, Runtime.getRuntime().availableProcessors()).stream()
.parallel().map(YourClass::parallelDeleteOperation).anyMatch(ret -> ret == false); // if any is false, it gives you false
}
// split up the list into "count" lists;
private static <T> List<List<T>> splitList(List<T> list, int count) {
List<List<T>> listList = new ArrayList<>();
for (int i = 0, blockSize = list.size() / count; i < count; ++i) {
listList.add(list.subList(i * blockSize, Math.min((i+1) * blockSize, list.size()));
}
return listList;
}
答案 1 :(得分:0)
我看不到将列表分为4个子列表的任何优势:线程终止其列表后,它将立即处于空闲状态。如果您为输入列表中的每个元素提交任务,则所有四个线程将处于活动状态,直到队列为空。
更新:
就像有人指出的那样,您可以使用parallelStream
,它更简单并且可能更快;但是如果您想保留ExecutorService
,则可以执行以下操作:
int noCores = Runtime.getRuntime().availableProcessors();
List<Future<Boolean>> futures = new ArrayList<>();
ExecutorService service = Executors.newFixedThreadPool(noCores);
try {
for (Structure s: listDir) {
String name = s.filename;
String filePath = "/" + (parent.isEmpty() ? "" : (parent
+ "/")) + name;
Future<Boolean> result = service.submit(()-> {
final DeleteMessage message = new DeleteMessage(
name, place, node, filePath);
return delete(message, groups, Uid, place);
});
futures.add(result);
}
} finally {
service.shutdown();
}