Существует множество способов отслеживания проблем с производительностью и неожиданно трудоемких методов, от быстрого и простого измерения времени от начала до конца метода до более полного (и сложного) CPU flamegraph или даже классики, такой как дамп потока, профилирование процессора и т. Д.
Во многих случаях для отладки достаточно просто поработать с метками времени и сравнить их. Но с асинхронной парадигмой это может быть слишком наивным способом.
Например, в контексте RxJava такого рода утверждения в методе:
Instant start = Instant.now(); Flowable- promise = itemRepository.findAllById(idList); log.info("{}", Duration.between(start, Instant.now()); return promise;
на самом деле не будет регистрироваться время, затраченное на извлечение хранилища.
Сделать старое снова новым
К счастью, RxJava поставляется с удобным оператором для измерения того, сколько времени и наблюдений прошло с момента подписки до ее завершения: timeInterval() (У реактора есть аналогичный оператор, о котором я расскажу позже)
временной интервал() doc объясняет, что он будет измерять длительность в миллисекундах и заключать ранее выданное значение в объект, содержащий как значение, так и измеренную задержку. В предыдущем примере Текучий<Элемент> стал бы Текучий<Приуроченный<Элемент>> .
Таким образом, мы можем написать наш код следующим образом:
return itemRepository.findAllById(idList)
.timeInterval()
.map(timed -> {
log.info("{}", timed.time());
timed.value();
});
На этот раз мы эффективно регистрируем продолжительность получения товаров.
Но все еще есть тонкость: выполнение этого на потоке может привести к фатальному получению журнала для каждого элемента, обратите внимание на общее. Что делать, если я выполняю вызовы API для множества элементов? Вот и все:
Flowable.fromIterable(idList)
.map(apiClient::getItemInfo)
.timeInterval()
.map(timed -> {
log.info("{}", timed.time());
return timed.value();
});
Мы получим журнал для каждого идентификатора, так как у нас много вызовов API и столько же подписок на .map(ApiClient::getItemInfo) .
Вы тоже говорили о Реакторе
Реактор предоставляет свой собственный оператор, называемый истекший() . Это очень похоже на его возврат a Поток<Кортеж2 <<< , кортеж2, имеющий методы gett1() (получить левое значение, здесь длительность в миллисекундах) и getT2() (получить правильное значение, значение, выданное предыдущим вызовом).
Таким образом, приведенный выше код будет выглядеть следующим образом:
Flux.fromIterable(idList)
.map(apiClient::getItemInfo)
.elapsed()
.map(tuple -> {
log.info("{}", tuple.getT1());
return tuple.getT2();
});
Теперь представьте, что вы где-то разместили статическую длинную сводную статистику и готовы быстро экспортировать минимальные/максимальные, средние и подсчеты относительно сложного набора операций, таких как, например, вызов двух API, объединение их результатов и помещение некоторой информации в кэш Redis.
Оригинал: “https://dev.to/sourcemancer/easy-time-tracing-in-rxjava-and-reactor-2de4”