2016-03-27 5 views
-3

У меня есть два фрагмента кода, которые технически одинаковы, но второй занимает 1 секунду, а затем первый. Первый один выполняет в 6 секунд, а второй в 7CompletedFuture занимает больше времени - Java 8

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

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

выше один принимает 6s и возьмётся 7s Here is the link to code

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

Пожалуйста, объясните, почему второй код последовательно занимает 1s больше (дополнительное время), по сравнению с первым

Ниже приведен сигнатура метода getYearlyEarningForUserWithEmployer. Только обмен, но это не должно иметь никакого влияние

Double getYearlyEarningForUserWithEmployer(long userId, long employerId); 

Here is the link to code

+0

Можете ли вы дать фрагмент занятостиService.getYearlyEarningForUserWithEmployer() – Naruto

+0

Как это сделать? – Robin

+0

Пожалуйста, сделайте [mcve]. – Tunaki

ответ

0

То, что Холгер сказал, имеет смысл, но не в проблеме, которую я опубликовал. Я согласен с тем, что вопрос не написан наилучшим образом.

Проблема заключалась в том, что порядок, в котором были написаны фьючерсы, вызывал последовательное увеличение времени.

В идеале порядок будущего не имеет значения до тех пор, как код написан в правильной реактивной моды

Причина проблемы была по умолчанию ForkJoinPool Явы и Java использует этот пул по умолчанию для запуска всех Завершенные фьючерсы. Если я запустил все CompletableFutues с настраиваемым пулом, я получаю почти то же самое время, независимо от порядка, в котором были написаны будущие заявления.

Мне все еще нужно выяснить, каковы ограничения ForkJoinPool и найти, почему мой собственный пул из 20 потоков работает лучше.

Я обновлю свой ответ, когда найду правильную причину.

0

Ваш вопрос ужасно неполный, но от того, что мы можем предположить, что это вполне вероятно, что второй вариант занимает больше времени, если мы предположим, что currencyConvCF представляет собой асинхронную операцию, которая может выполняться одновременно, пока выполняются ваши фрагменты кода, и вы говорите об общем времени, которое требуется для завершения всех операций, включая тот, который представлен CompletableFuture, возвращенный thenApplyAsync (earlyEarningsInHomeCountryCF).

В первом варианте вы вызываете getYearlyEarningForUserWithEmployer, а операция, представленная currencyConvCF, может быть запущена одновременно. Умножение произойдет, когда обе операции будут завершены.

Во втором варианте getYearlyEarningForUserWithEmployer вызов является частью операции, переданного currencyConvCF.thenApplyAsync, таким образом, она не будет начинаться до операции, представленное currencyConvCF была завершена, так что никакие операции не будут работать одновременно. Если предположить, что getYearlyEarningForUserWithEmployer занимает значительное время, скажем одну секунду, и не имеет внутренних зависимостей для другой операции, неудивительно, когда общая операция занимает больше времени в этом варианте.

Кажется, что вы действительно хотите сделать что-то вроде:

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

так getYearlyEarningForUserWithEmployer не выполняется последовательно в инициирующей потоке, но обе операции источника могут работать асинхронно, прежде чем применяется окончательное умножение.

Однако, когда вы вызываете get прямо в инициирующем потоке, как в вашем связанном коде github, эта асинхронная обработка второй операции не имеет преимущества. Вместо того, чтобы ждать завершения, ваш инициирующий поток может просто выполнить независимую операцию, поскольку второй вариант кода вашего вопроса уже выполняется, и вы, скорее всего, будете еще быстрее, если не создадите асинхронную операцию для чего-то столь же простого, как одно умножение, т.е. используйте вместо этого:

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