2017-09-27 197 views
0

假設我想要並行發送多個數據庫查詢(或web服務請求),並在之後進行聚合。我會更好地使用stream API還是CompletableFuture使用Stream API或CompletableFuture進行並行db查詢?

STREAM:

List<Result> result = requests.parallelStream() 
           .map(req -> query(req.getFirstname, req.getLastname)) 
           .collect(toList()); 

//a database, or a webservice 
private Result query(firstname, lastname); 

期貨:

List<CompletableFuture> futures; 
for (QueryReq req: requests) { //given input 
    futures.add(CompletableFuture 
         .supplyAsync(() -> query(req.getFirstname, req.getLastname)); 
} 

//wait for all futures to complete and collect the results 
List<Result> results = new ArrayList<>(); 
for (CompleteableFuture f : futures) { 
    results.add(f.get()); 
} 

雖然流肯定是更簡潔,但哪一個應首選是什麼原因呢?

旁註:我知道我可以用sql = :firstname IN (..) and ... :lastname IN(..)更容易地查詢這個例子。但這只是使用流或期貨的一個例子。

該任務也可以並行發送多個webservice請求,而不是db查詢。

+1

你會讀這嗎?它可能無法工作... https://stackoverflow.com/questions/44029856/using-jpa-objects-in-parallel-streams-with-spring – Eugene

+0

我會說廣泛和基於意見。主要的牛肉是相同的(並行運行的東西),你的示例代碼甚至都使用公共池。我想說這主要取決於其他代碼的存在。 – Kayaman

+0

@Eugene當然取決於你在什麼時候將EntityManager綁定到線程。給出的例子並未顯示與鏈接問題類似的「線程交叉」。 – Kayaman

回答

1

正如您已經說過的:「流確實不那麼冗長」,是不是更喜歡使用Stream?公平起見,我認爲我們也應該用Java 8 Stream APIs重寫第二個示例代碼CompletableFuture

List<Result> result = requests.stream() 
     .map(req -> CompletableFuture.supplyAsync(() -> query(req.getFirstname, req.getLastname))) 
     .collect(toList()).stream() 
     .map(f -> f.get()).collect(toList()); 

看起來它仍然是很多冗長/長於:

List<Result> result = requests.parallelStream() 
     .map(req -> query(req.getFirstname, req.getLastname)).collect(toList()); 

不過,我認爲這裏的關鍵點是如何設置的併發線程數:通過並行流,線程數是固定的通過ForkJoinPool.commonPool,CPU核心號。通常這對於發送大量的web/db請求來說太小了。例如,如果有數十/數百個web/db請求發送,大多數情況下,發送具有20個或更多線程的請求的速度要快於ForkJoinPool.commonPool中定義的線程數。個人而言,我也不知道用什麼方便的方式來指定並行流中的線程號。這裏有一些你可以參考的答案:custom-thread-pool-in-java-8-parallel-stream

+0

所以我認爲可以得出結論:如果只需要幾個並行線程,就使用'streams', CompletableFuture'爲更多數量的並行+來控制池大小。 – membersound

+0

沒錯。如果並行流提供的線程數足夠。沒有理由不使用並行數據流,畢竟這很容易/簡單。不幸的是,CompletableFuture:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#runAsync-java.lang.Runnable-也使用ForkJoinPool.commonPool()。你需要找到我發佈的問題的方式/答案。 –