[英]using parallelStream for independent tasks?
我有一個任務清單。 每個任務彼此獨立(它們不使用彼此的結果)。
當有 1000 個任務並使用順序 stream 來處理這些任務時..
tasks.forEach(task->{
// long running task
task.run();
System.out.println("Thread: " + Thread.currentThread().getName());
});
..然后,第二個任務在第一個任務之后運行,依此類推。 循環以阻塞和順序模式運行(第二個任務僅在第一個任務完成后完成)。
並行處理每個任務的最佳方法是什么?
這是最好的方法嗎?
tasks.parallelStream().forEach(task->{
// long running task
task.run();
System.out.println("Thread: " + Thread.currentThread().getName());
});
根據我是否應該盡可能使用並行 stream? ,應避免使用並行流。 就我而言,這些任務彼此獨立,我不需要使用parallelStream()
帶來的同步開銷。 但是,在使用parallelStream()
時沒有禁用同步開銷的選項。 或者?
對於我的用例,有沒有比parallelStream()
更好的方法?
在 Java 8 parallelStream()
中,使用在 JVM 啟動時初始化的ForkJoinCommonPool
並包含固定數量的線程,這些線程更適合遵循“分而治之”范式的工作。 在您的情況下,由於它們都是隔離的,因此使用ExecutorService
可能更合適。
一個好的解決方案是使用CompletableFuture.allOf
。 像這樣使用它:
ExecutorService ex = //Whatever executor you want;
CompletableFuture.allOf((CompletableFuture<Void>[]) tasks.stream()
.map(task -> CompletableFuture.runAsync((() -> /* Do task */), ex))
.toArray());
這樣做,您可以執行異步、非阻塞。 此外,您將收到有關類型轉換的編譯器警告,但我認為在您的情況下,忽略它可能是安全的。
ExecutorService.submit
將觸發任務,但是當您使用get
獲取任何結果時,它將阻塞然后檢索。 CompletableFuture
在獲取數據時不會阻塞。 當您希望在所有並行任務完成后查看返回的某種結果時,就會出現這種情況。
更多解釋可以在這里找到。
此外,在您最初的問題中,您詢問使用parallelStream
是否是一個好主意,而我對此的回答是這不是一個好主意,因為如果有一個任務阻塞了線程,那么您將遇到問題(假設您在代碼中的所有地方都使用了parallelStream
)。
此外, CompletableFuture
可以接受它自己的線程池(您可以自定義)並在那里運行。 注意上面代碼中runAsync
的第二個參數。
如果您只是想擁有一個“一勞永逸”的機制並且不關心結果,那么使用ExecutorService.invokeAll
是一個很好的方法。 你可以像這樣使用它:
executorService.invokeAll(tasks.stream().map(task -> new Callable<Void>() {
@Override
public Void call() throws Exception {
// run task;
return null;
}
})
.collect(Collectors.toList()));
但是在這種情況下,為什么要使用CompletableFuture
和自己的ExecutorService
呢?
一個很好的理由是流暢的錯誤處理。 你可以在這里和這里看到一些例子
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.