执行时间反应式编程

时间:2018-07-05 21:04:35

标签: spring reactive-programming project-reactor

这是在反应式编程中查找方法(getFavourites)执行时间的理想方法吗?

public List<Favourites> getFavouriteDetails(String userId){
    userService.getFavorites(userId) 
               .flatMap(favoriteService::getDetails) 
               .switchIfEmpty(suggestionService.getSuggestions()) 
               .take(5) 
               .publishOn(UiUtils.uiThreadScheduler()) 
               .subscribe(uiList::show, UiUtils::errorPopup)
               .flatMap(a -> Mono.subscriberContext().map(ctx -> {
                         log.info("Time taken : " + Duration.between(ctx.get(key), Instant.now()).toMillis() + " milliseconds.");
                         return a;
                     }))
               .subscriberContext(ctx -> ctx.put(key, Instant.now()))
}

2 个答案:

答案 0 :(得分:3)

两种方法可确保仅在订阅时衡量执行时间-

  • 使用flatMapMany将Mono环绕在助焊剂上。这也会返回磁通量。
  • 使用AtomicReference,在onSubscribe中设置时间,并在doFinally中记录经过的时间。

示例代码-

timeFluxV1(getFavouriteDetails(userId)).subscribe(uiList::show, UiUtils::errorPopup);

timeFluxV1(getFavouriteDetails(userId)).subscribe(uiList::show, UiUtils::errorPopup);
 
private <T>  Flux<T> timeFluxV1(Flux<T> flux) {
    return Mono.fromSupplier(System::nanoTime)
             .flatMapMany(time -> flux.doFinally(sig -> log.info("Time taken : " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - time) + " milliseconds.")));
}


private <T>  Flux<T> timeFluxV2(Flux<T> flux) {
    AtomicReference<Long> startTime = new AtomicReference<>();
    return flux.doOnSubscribe(x -> startTime.set(System.nanoTime()))
            .doFinally(x -> log.info("Time taken : " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime.get()) + " milliseconds."));
}

public Flux<Favourites> getFavouriteDetails(String userId) {
    return userService.getFavorites(userId)
               .flatMap(favoriteService::getDetails) 
               .switchIfEmpty(suggestionService.getSuggestions()) 
               .take(5) 
               .publishOn(UiUtils.uiThreadScheduler());
}

答案 1 :(得分:1)

要计时某个方法,Java中最基本的方法是使用long System.nanoTime()InstantSystem.currentTimeMillis用于壁钟操作,不保证其单调或不够精确...

在Reactor中,要测量一个序列完成所花费的时间,通常需要启动订阅计时(直到您订阅之前什么都不会发生),并在doFinally(在其中执行一些代码)内停止计时主序列的一侧,只要它完成,出错或被取消)。

但是,这里您要订阅自己,因此不存在多个订阅的风险。因此,您可以消除“订阅开始时间”约束。

它给我们这样的东西:

public List<Favourites> getFavouriteDetails(String userId){
    final long start = System.nanoTime();
    userService.getFavorites(userId) 
               .flatMap(favoriteService::getDetails) 
               .switchIfEmpty(suggestionService.getSuggestions()) 
               .take(5) 
               .publishOn(UiUtils.uiThreadScheduler())
               .doFinally(endType -> log.info("Time taken : " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start) + " milliseconds."))
               .subscribe(uiList::show, UiUtils::errorPopup);
    //return needed!
}

请注意,还有一个elapsed()运算符,用于测量预订与第一个onNext之间以及随后的onNext之间的时间。它输出一个Flux<Tuple2<Long, T>>,您可以汇总多头以获得总体时间,但是在这种情况下,这将使您失去T的“实时”性质。