Два дня назад я написал статью о«Ошибка в руководстве по разработке Java для Ali»статьи, область комментариев немного жарит, в основном разделена на две фракции: те, кто поддерживает Лао Вана, и те, кто сомневается в Лао Ване.
Прежде всего, независимо от того, с какой стороны, я искренне благодарю вас. В частности, «Второй старший брат» изначально планировал хорошенько отдохнуть в пятницу вечером (статья, опубликованная в пятницу вечером), но поскольку он обсуждал со мной этот вопрос, то получил его примерно до 12 часов вечера. видно, что он хорошо разбирается в технике. Мы такие же в этом вопросе, и, как и вы, читающие эту статью,Мы относимся к категории людей, бесконечно одержимых технологиями.
Значение правильного и неправильного
На самом деле, когда я готовился опубликовать эту статью, я уже предвидел эту ситуацию.Когда вы вопрошаете, не важно, правильно это или неправильно, должны быть противоположные голоса, потому что у других тоже есть право на вопрос, и что вы должны делать в этот момент стоит постараться сохранять Спокойствие, понять и проверить эти вопросы с объективным отношением. И эти вопросы (разные голоса) со временем станут ценным активом, потому что вы обязательно что-то приобретете в этом процессе проверки.
В то же время, я также надеюсь, что мое понимание ошибочно, потому что, как и все, я также являюсь верным "верующим" "Руководству по разработке Java" Али, но я случайно мельком увидел "разницу", а затем поделился своими идеями и результат у всех..
Но я также считаю, что любой "авторитет" имеет возможность ошибаться. Наши предки когда-то говорили нам, что "люди, которые не являются святыми и мудрецами, могут ошибаться". Мне не нужно беспокоиться о том, кто прав, а кто виноват, наоборотЯ считаю, что слепо гоняться за тем, кто прав, а кто виноват, очень наивно., только дети делают это, что мы должны сделать, этоОбсуждая «правильно и неправильно» в этом вопросе, мы можем получить больше знаний и помочь нам стать лучше., в этом смысл моей сегодняшней статьи.
Джобс однажды сказал:Мне больше всего нравится работать с умными людьми, потому что им не нужно беспокоиться о своем достоинстве. Я не умный человек, но я знаю, что за любой «неправильной вещью» должна стоять какая-то ценность. Поэтому я не боюсь получить "пощечину".Если вы хотите быстро расти, советую вам сделать то же самое.
Ладно, на этом пока все, давайте перейдем к сегодняшней теме.
оппозиция
Основные пункты друзей, придерживающихся разных взглядов, следующие:
Я разобрал эти комментарии.На самом деле я сказал одно.Давайте сначала посмотрим на содержание исходного текста.
В «Руководстве по разработке Java» Taishan Edition (последнее издание) это указано в четвертой спецификации третьего подраздела второй главы:
[Обязательно] Используйте заполнители для объединения строковых переменных во время вывода журнала.
Примечание. Поскольку при сращивании строк String будет использоваться метод append() StringBuilder, производительность несколько снижается. Использование заполнителей — это только заменяющее действие, которое может эффективно улучшитьпредставление.
Положительный пример: logger.debug("Обработка сделки с id: {} и symbol: {}", id, symbol);
Оппонент (обратите внимание, что это «оппозиция» — не уничижительный термин, а для лучшего разграничения ролей) означает это:
Использование заполнителя сначала оценивает выходной уровень журнала, а затем решает, следует ли объединять выходные данные, в то время как прямое использование StringBuilder сначала выполняет объединение, а затем оценку, в этом случае, когда уровень журнала установлен относительно высокий, потому что StringBuilder объединяется. Сначала он оценивается снова, что приводит к пустой трате системных ресурсов, поэтому способ использования заполнителей имеет более высокую производительность, чем способ StringBuilder.
Отложим в сторону, отражен ли упомянутый оппонентами смысл в "Руководстве по разработке Java" Али, потому что я действительно его не видел, проследим за этим ходом размышлений, чтобы подтвердить правильность вывода.
Оценка эффективности
Это все еще старое правило, давайте поговорим с данными и кодом, Чтобы проверить, что JMH (инструмент тестирования) может хорошо сочетаться с Spring Boot, первое, что нам нужно сделать, это проверить, может ли настройка уровня вывода журнала вступить в силу. в тестовом коде JMH.
Тогда давайте сначала напишем тестовый код для «установки уровня журнала»:
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.boot.SpringApplication;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime) // 测试完成时间
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) // 预热 2 轮,每次 2s
@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 3s
@Fork(1) // fork 1 个线程
@State(Scope.Thread) // 每个测试线程一个实例
@Slf4j
public class LogPrintAmend {
public static void main(String[] args) throws RunnerException {
// 启动基准测试
Options opt = new OptionsBuilder()
.include(LogPrintAmend.class.getName() + ".*") // 要导入的测试类
.build();
new Runner(opt).run(); // 执行测试
}
@Setup
public void init() {
// 启动 spring boot
SpringApplication.run(DemoApplication.class);
}
@Benchmark
public void logPrint() {
log.debug("show debug");
log.info("show info");
log.error("show error");
}
}
В тестовом коде мы используем 3 уровня директив логирования вывода:debug
уровень,info
уровень иerror
уровень.
Затем задаем уровень вывода лога в конфигурационном файле (application.properties), конфигурация следующая:
logging.level.root=info
Видно, что мы установили все уровни вывода лога наinfo
уровне, а затем выполняем указанную выше программу, результат выполнения следующий:
Как видно из рисунка выше, журнал выводит толькоinfo
иerror
level, то есть установленный нами уровень вывода лога вступает в силу.Для обеспечения защиты от дурака мы снизим уровень вывода лога доdebug
уровень, результаты теста показаны на следующем рисунке:
Как видно из приведенных выше результатов, в установленном нами уровне логирования нет ничего плохого, т.е.Фреймворк JMH можно хорошо использовать с SpringBoot..
Советы, вес уровня журнала: TRACE
Давайте проверим его с помощью приведенной выше основы настройки уровня журнала.Если вы сначала соедините строки, а затем оцените производительность вывода и результаты оценки производительности заполнителя, полный тестовый код будет следующим:
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.boot.SpringApplication;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime) // 测试完成时间
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) // 预热 2 轮,每次 2s
@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 3s
@Fork(1) // fork 1 个线程
@State(Scope.Thread) // 每个测试线程一个实例
@Slf4j
public class LogPrintAmend {
private final static int MAX_FOR_COUNT = 100; // for 循环次数
public static void main(String[] args) throws RunnerException {
// 启动基准测试
Options opt = new OptionsBuilder()
.include(LogPrintAmend.class.getName() + ".*") // 要导入的测试类
.build();
new Runner(opt).run(); // 执行测试
}
@Setup
public void init() {
SpringApplication.run(DemoApplication.class);
}
@Benchmark
public void appendLogPrint() {
for (int i = 0; i < MAX_FOR_COUNT; i++) { // 循环的意图是为了放大性能测试效果
// 先拼接
StringBuilder sb = new StringBuilder();
sb.append("Hello, ");
sb.append("Java");
sb.append(".");
sb.append("Hello, ");
sb.append("Redis");
sb.append(".");
sb.append("Hello, ");
sb.append("MySQL");
sb.append(".");
// 再判断
if (log.isInfoEnabled()) {
log.info(sb.toString());
}
}
}
@Benchmark
public void logPrint() {
for (int i = 0; i < MAX_FOR_COUNT; i++) { // 循环的意图是为了放大性能测试效果
log.info("Hello, {}.Hello, {}.Hello, {}.", "Java", "Redis", "MySQL");
}
}
}
Видно, что используется кодinfo
уровень данных журнала, то мы устанавливаем уровень журнала в файле конфигурации больше, чемinfo
изerror
уровне, а затем выполните приведенный выше код, результаты теста будут следующими:
Вау, какой удовлетворительный результат теста. Из приведенных выше результатов мы видим, что производительность использования заполнителей действительно лучше, чемStringBuilder
Путь гораздо выше, а значит, "Руководство по разработке Java" Али не проблема.
обеспечить регресс
Но все не так просто, например, когда вы идете по дороге, к вам приближается велосипед и он вот-вот столкнется с вами, что вы будете делать в это время? Без сомнения, вы будете подсознательно избегать этого.
Так что то же самое верно и для приведенной выше оценки, зачем судить после сращивания строк?
Если программирование уже является вашим официальным занятием, то оценка, а затем сращивание строк является самым основным требованием к профессиональным навыкам. Это та же причина, по которой вы будете подсознательно избегать велосипеда, который столкнулся лоб в лоб. Если вы полностью способны, Избегая проблем , вы должны сначала избежать проблем, а потом выполнять другие операции, иначе, когда команда проверит код или уволит сотрудников в конце месяца, вы должны быть первым «пострадавшим» объектом. Потому что такие простые (неправильные) вопросы возможны только для новичков, которые только начинают.
Тогда в соответствии с самыми основными требованиями программы мы должны написать такой код:
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.boot.SpringApplication;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime) // 测试完成时间
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) // 预热 2 轮,每次 2s
@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 3s
@Fork(1) // fork 1 个线程
@State(Scope.Thread) // 每个测试线程一个实例
@Slf4j
public class LogPrintAmend {
private final static int MAX_FOR_COUNT = 100; // for 循环次数
public static void main(String[] args) throws RunnerException {
// 启动基准测试
Options opt = new OptionsBuilder()
.include(LogPrintAmend.class.getName() + ".*") // 要导入的测试类
.build();
new Runner(opt).run(); // 执行测试
}
@Setup
public void init() {
SpringApplication.run(DemoApplication.class);
}
@Benchmark
public void appendLogPrint() {
for (int i = 0; i < MAX_FOR_COUNT; i++) { // 循环的意图是为了放大性能测试效果
// 再判断
if (log.isInfoEnabled()) {
StringBuilder sb = new StringBuilder();
sb.append("Hello, ");
sb.append("Java");
sb.append(".");
sb.append("Hello, ");
sb.append("Redis");
sb.append(".");
sb.append("Hello, ");
sb.append("MySQL");
sb.append(".");
log.info(sb.toString());
}
}
}
@Benchmark
public void logPrint() {
for (int i = 0; i < MAX_FOR_COUNT; i++) { // 循环的意图是为了放大性能测试效果
log.info("Hello, {}.Hello, {}.Hello, {}.", "Java", "Redis", "MySQL");
}
}
}
даже поставитьif
Упомянутое решениеfor
вне цикла, ноfor
Он представляет собой не конкретный бизнес, а код, написанный для лучшего усиления тестового эффекта, поэтому мы напишем суждение вfor
внутри петли.
Затем давайте снова выполним тестовый код в это время, и результат выполнения будет таким, как показано на следующем рисунке:
Из приведенных выше результатов видно, что метод использования первой оценки, а затем объединения строк все еще более эффективен, чем использование заполнителей.
Так,У нас до сих пор нет возможности доказать высокую эффективность плейсхолдеров в «Руководстве по разработке Java» Али..
Так что я все еще придерживаюсь своего мнения,Использование заполнителей вместо сращивания строк может в основном обеспечить элегантность кода, и вы можете делать менее логические суждения в коде, но это не имеет ничего общего с производительностью..
Расширенные знания: форматирование журналов
В приведенном выше процессе оценки мы обнаружили, что выходной формат журнала очень "хаотичен". Есть ли способ отформатировать журнал?
Ответ: да, вывод журнала по умолчанию выглядит следующим образом:
Можно настроить для форматирования журнала весеннего загрузкиlogging.pattern.console
варианты, пример конфигурации выглядит следующим образом:
logging.pattern.console=%d | %msg %n
Вывод журнала выглядит следующим образом:
Видно, что после форматирования журнала содержимое простое, но нельзя отказываться от ключевой отладочной информации из-за простоты и пропускать вывод.
Суммировать
В этой статье мы протестировали оценку производительности сплайсинга строк и заполнителей, заданную читателями, и обнаружили, что точка зрения о том, что метод заполнителя имеет высокую производительность, до сих пор не может быть проверена, поэтому наша основная точка зрения по-прежнему такова.Способ использования плейсхолдеров более элегантен, и можно добиться большего количества функций с меньшим количеством кода; что касается производительности, то можно сказать только, что она неплохая, но и не отличная.. В конце статьи мы говорили о знании форматирования журнала Spring Boot. Я надеюсь, что эта статья может помочь вам практически. Вы также можете оставить сообщение в области комментариев, чтобы пообщаться со мной.
последние слова
Оригинальность непростая, вы видели это, нажмите "отличный«Пойдем еще раз, это самая большая поддержка и ободрение для меня, спасибо!
Подпишитесь на официальный аккаунт «Java Chinese Community» и ответьте на «Галантные товары», чтобы получить 50 оригинальных галантерейных товаров.Топ-лист.