2016-03-27 1 views
-3

J'ai deux extraits de code qui sont techniquement identiques, mais le second prend 1 seconde de plus que le premier. Le premier exécute en 6 sec et le deuxième 7.CompletableFuture prend plus de temps - Java 8

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

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

celui ci-dessus prend 6s et la suivante se 7s Here is the link to code

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

S'il vous plaît expliquer pourquoi le second code prend toujours plus 1s (temps supplémentaire) par rapport à la première

Ci-dessous, la signature de la méthode getYearlyEarningForUserWithEmployer. Il suffit de partager, mais il ne devrait avoir aucun effet

Double getYearlyEarningForUserWithEmployer(long userId, long employerId); 

Here is the link to code

+0

Pouvez-vous donner un extrait de employmentService.getYearlyEarningForUserWithEmployer() – Naruto

+0

Comment cela fait-il la différence? – Robin

+0

Veuillez faire un [mcve]. – Tunaki

Répondre

0

Tout ce que Holger a dit a du sens, mais pas dans le problème que j'ai posté. Je suis d'accord que la question n'est pas écrite de la meilleure façon.

Le problème était que l'ordre dans lequel les contrats à terme étaient écrits entraînait une augmentation constante du temps.

Idéalement l'ordre de l'avenir ne devrait pas d'importance tant que le code est écrit de façon réactive correcte

La raison du problème était la valeur par défaut ForkJoinPool de Java et Java utilise ce pool par défaut pour exécuter tous les CompletableFutures. Si je cours tous les CompletableFutues avec un pool personnalisé, je reçois presque le même temps, indépendamment de l'ordre dans lequel les futures déclarations ont été écrites.

Je dois encore trouver quelles sont les limites de ForkJoinPool et trouver pourquoi mon pool personnalisé de 20 threads fonctionne mieux.

Je mettrai à jour ma réponse lorsque je trouverai la bonne raison.

0

Votre question est horriblement incomplète, mais de ce que nous pouvons le deviner, il est tout à fait plausible que la deuxième variante prend plus de temps, si l'on suppose que currencyConvCF représente une opération asynchrone qui peut s'exécuter simultanément lorsque vos fragments de code sont exécutés et que vous parlez du temps total nécessaire pour effectuer toutes les opérations, y compris celui représenté par le CompletableFuture renvoyé par thenApplyAsync (earlyEarningsInHomeCountryCF).

Dans la première variante, vous appelez getYearlyEarningForUserWithEmployer alors que l'opération représentée par currencyConvCF est peut-être toujours en cours d'exécution. La multiplication aura lieu lorsque les deux opérations seront terminées.

Dans la deuxième variante, l'invocation getYearlyEarningForUserWithEmployer fait partie de l'opération est passé à currencyConvCF.thenApplyAsync, donc il ne démarre pas avant que l'opération représentée par currencyConvCF est terminée, donc aucune opération se déroulera en même temps. Si nous supposons que getYearlyEarningForUserWithEmployer prend un temps significatif, disons une seconde, et n'a pas de dépendances internes à l'autre opération, il n'est pas surprenant quand l'opération globale prend plus de temps dans cette variante.

Il semble, en fait ce que vous voulez faire est quelque chose comme:

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

si getYearlyEarningForUserWithEmployer n'est pas exécuté de façon séquentielle dans le thread initiant mais les deux opérations de source peuvent fonctionner de manière asynchrone avant la multiplication finale s'applique.

Cependant, lorsque vous appelez get immédiatement après dans le thread initiateur, comme dans votre code lié sur github, ce traitement asynchrone de la seconde opération n'a aucun avantage. Au lieu d'attendre l'achèvement, votre thread initiateur peut simplement effectuer l'opération indépendante comme le fait déjà la deuxième variante de code de votre question et vous serez probablement encore plus rapide lorsque vous ne lancez pas une opération asynchrone pour quelque chose d'aussi simple qu'une simple multiplication. à la place:

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