2016-03-27 11 views
-3

Ich habe zwei Codeschnipsel, die technisch identisch sind, aber die zweite dauert 1 Sekunde mehr als die erste. Die erste führt in 6 sec und die zweite in 7.CompletableFuture braucht mehr Zeit - Java 8

Double yearlyEarnings = employmentService.getYearlyEarningForUserWithEmployer(userId, emp.getId()); 

CompletableFuture<Double> earlyEarningsInHomeCountryCF = currencyConvCF.thenApplyAsync(currencyConv -> { 
    return currencyConv * yearlyEarnings; 
}); 

Die oben nimmt man 6S und der nächste nimmt 7S Here is the link to code

CompletableFuture<Double> earlyEarningsInHomeCountryCF = currencyConvCF.thenApplyAsync(currencyConv -> { 
     Double yearlyEarnings = employmentService.getYearlyEarningForUserWithEmployer(userId, emp.getId()); 
     return currencyConv * yearlyEarnings; 
}); 

Bitte beschreiben konsequent der zweite Code dauert 1s mehr (Extrazeit) als eine mit dem ersten verglichen

Unten ist die Signatur der Methode getYearlyEarningForUserWithEmployer. Nur teilen, aber es sollte nicht

Double getYearlyEarningForUserWithEmployer(long userId, long employerId); 

Here is the link to code

+0

Können Sie Snippet von employmentService.getYearlyEarningForUserWithEmployer() geben – Naruto

+0

Wie macht es einen Unterschied? – Robin

+0

Bitte machen Sie ein [mcve]. – Tunaki

Antwort

0

Was immer Holger sagte macht Sinn, aber nicht in dem Problem, das ich gepostet habe. Ich stimme zu, dass die Frage nicht in der besten Weise geschrieben ist.

Das Problem war, dass die Reihenfolge, in der die Futures geschrieben wurden, eine konsistente Zunahme der Zeit verursachte.

Idealerweise wird die Reihenfolge der Zukunft sollte nicht so lange egal, wie der Code in einer richtigen reaktiven Art und Weise geschrieben

Der Grund des Problems war das Standard-ForkJoinPool von Java und Java verwendet diesen Pool standardmäßig alle laufen die CompletableFutures. Wenn ich alle CompletableFutues mit einem benutzerdefinierten Pool ausführen, bekomme ich fast die gleiche Zeit, unabhängig von der Reihenfolge, in der die zukünftigen Anweisungen geschrieben wurden.

Ich muss immer noch finden, was sind die Einschränkungen von ForkJoinPool und finden Sie, warum meine benutzerdefinierte Pool von 20 Threads besser funktioniert.

Ich werde meine Antwort aktualisieren, wenn ich den richtigen Grund finde.

0

Ihre Frage schrecklich unvollständig beeinflussen, aber von dem, was wir denken können, ist es durchaus plausibel, dass die zweite Variante länger dauert, wenn wir davon ausgehen, dass currencyConvCF stellt einen asynchronen Vorgang dar, der möglicherweise gleichzeitig ausgeführt wird, während Ihre Codefragmente ausgeführt werden, und Sie sprechen von der Gesamtzeit, die für die Ausführung aller Vorgänge benötigt wird, einschließlich der von CompletableFuture zurückgegebenen thenApplyAsync (earlyEarningsInHomeCountryCF).

In der ersten Variante rufen Sie getYearlyEarningForUserWithEmployer auf, während die durch currencyConvCF dargestellte Operation möglicherweise noch gleichzeitig ausgeführt wird. Die Multiplikation erfolgt, wenn beide Operationen abgeschlossen sind.

In der zweiten Variante wird der getYearlyEarningForUserWithEmployer Aufruf ist Teil der Operation zu currencyConvCF.thenApplyAsync vergangen, so wird es nicht gestartet werden, bevor die durch currencyConvCF dargestellte Operation abgeschlossen war, so wird keine Operation gleichzeitig ausgeführt werden. Wenn wir annehmen, dass getYearlyEarningForUserWithEmployer eine beträchtliche Zeit braucht, sagen wir eine Sekunde, und keine internen Abhängigkeiten zu der anderen Operation hat, ist es nicht überraschend, wenn die gesamte Operation in dieser Variante länger dauert.

Es scheint, was Sie eigentlich tun wollen so etwas wie:

CompletableFuture<Double> earlyEarningsInHomeCountryCF = currencyConvCF.thenCombineAsync(
    CompletableFuture.supplyAsync(
     () -> employmentService.getYearlyEarningForUserWithEmployer(userId, emp.getId())), 
    (currencyConv, yearlyEarnings) -> currencyConv * yearlyEarnings); 

so wird getYearlyEarningForUserWithEmployer in dem initiierenden Thread nicht nacheinander ausgeführt werden aber beide Quellvorgänge können asynchron ausgeführt werden, bevor die endgültige Multiplikation gilt.

Wenn Sie jedoch direkt im initiierenden Thread get aufrufen, wie in Ihrem verknüpften Code auf GitHub, hat diese asynchrone Verarbeitung der zweiten Operation keinen Vorteil. Anstatt auf die Vervollständigung zu warten, kann Ihr initiierender Thread nur die unabhängige Operation ausführen, wie es die zweite Codevariante Ihrer Frage bereits tut, und Sie werden wahrscheinlich noch schneller sein, wenn Sie keine asynchrone Operation für etwas so Einfaches wie eine einfache Multiplikation erzeugen stattdessen:

CompletableFuture<Double> currencyConvCF = /* a true asynchronous operation */ 
return employmentService.getYearlyEarningForUserWithEmployer(userId, emp.getId()) 
    * employerCurrencyCF.join();