英文:
CompletionService vs CompletableFuture
问题
以下是翻译好的部分:
我有1000个大文件需要按照下面提到的顺序进行处理:
- 首先,这些文件需要并行地复制到另一个目录中,我计划使用
ExecutorService
和10个线程来实现。 - 一旦任何文件被复制到另一个位置(#1),我将提交该文件以进一步在
ExecutorService
中使用10个线程进行处理。 - 最后,需要对这些文件执行另一个并行操作,就像#2从#1获取输入,#3从#2获取输入。
现在,我可以在这里使用CompletionService
,这样我就可以按照它们完成的顺序处理从#1到#2的线程结果,以及从#2到#3的线程结果。CompletableFuture
说我们可以将异步任务链接在一起,这听起来就像是我可以在这种情况下使用的东西。
我不确定是否应该使用CompletableFuture
来实现我的解决方案(因为它相对较新,应该更好),还是CompletionService
已经足够?在这种情况下,我为什么要选择其中之一?
英文:
I have 1000 big files to be processed in order as mentioned below:
- First those files needs to be copied to a different directory in parallel, I am planning to use
ExecutorService
with 10 threads to achieve it. - As soon as any file is copied to another location(#1), I will submit that file for further processing to
ExecutorService
with 10 threads. - And finally, another action needs to be performed on these files in parallel, like #2 gets input from #1, #3 gets input from #2.
Now, I can use CompletionService
here, so I can process the thread results from #1 to #2 and #2 to #3 in the order they are getting completed. CompletableFuture
says we can chain asynchronous tasks together which sounds like something I can use in this case.
I am not sure if I should implement my solution with CompletableFuture
(since it is relatively new and ought to be better) or if CompletionService
is sufficient? And why should I chose one over another in this case?
答案1
得分: 1
这种情况下,尝试两种方法然后选择你更为舒适的一种可能是最好的。虽然听起来 CompletableFuture
更适合这个任务,因为它们能够很轻松地链式处理步骤/阶段。例如在你的情况下,代码可能如下所示:
ExecutorService copyingExecutor = ...
// 根据需求不太清楚,但假设你有一个专门的执行器
ExecutorService processingExecutor = ...
public CompletableFuture<MyResult> process(Path file) {
return CompletableFuture
.supplyAsync(
() -> {
// 获取文件应该被复制到的目标路径
Path destination = ...
try {
Files.copy(file, destination);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return destination;
},
copyingExecutor
)
.thenApplyAsync(
copiedFile -> {
// 处理被复制的文件
...
},
processingExecutor
)
// 这个独立的阶段意义不大,所以除非你有另一个执行器用于此阶段,或者此阶段在代码中的不同位置应用,否则它可能应该与前一个阶段合并
.thenApply(
previousResult -> {
// 处理前一个结果
...
}
);
}
英文:
It would probably be best if you tried both approaches and then choose the one you are more comfortable with. Though it sounds like CompletableFuture
s are better suited for this task because they make chaining processing steps / stages really easy. For example in your case the code could look like this:
ExecutorService copyingExecutor = ...
// Not clear from the requirements, but let's assume you have
// a separate executor for this
ExecutorService processingExecutor = ...
public CompletableFuture<MyResult> process(Path file) {
return CompletableFuture
.supplyAsync(
() -> {
// Retrieve destination path where file should be copied to
Path destination = ...
try {
Files.copy(file, destination);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return destination;
},
copyingExecutor
)
.thenApplyAsync(
copiedFile -> {
// Process the copied file
...
},
processingExecutor
)
// This separate stage does not make much sense, so unless you have
// yet another executor for this or this stage is applied at a different
// location in your code, it should probably be merged with the
// previous stage
.thenApply(
previousResult -> {
// Process the previous result
...
}
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论