Как стать автором
Обновить

Комментарии 74

лимит инлайнинга в Hostpot JVM — 35 байткод инструкций
После этой ерунды можно дальше не читать. И что invokestatic якобы эффективнее invokevirtual, и что «лишние» push/pop якобы влияют на скорость — всё от начала и до конца — сплошная неправда. Уберите, пожалуйста, статью, чтоб не путать людей.

«Оптимизировать» программу на уровне байткода — всё равно что улучшать автомобиль, выкидывая «лишние» детали.
После этой ерунды можно дальше не читать.

А что тут не так? Может я как-то не правильно перевел.

всё от начала и до конца — сплошная неправда

У автора есть решение с открытым кодом, которым пользуются очень много людей. Есть бенчмарки, подтверждающие его слова. Все есть на гитхабе. Буду не против увидеть реальное опровержение слов автора.
Лучше приведите исходники этих бенчмарков (на гитхабе проекта не нашёл), и я скажу, где они врут.
Вы перевели всё честно, здесь спору нет, но ерунда написана в оригинальной статье.
Спасибо за ссылку.
Действительно, бенчмарк оказался ни о чём. Проверяются пустые стабы, не имеющие ничего общего с реальными Connection и Statement.

В таком случае наш Datasource почти в 4 раза быстрее на том же бенчмарке, и тогда заголовок статьи про «самый быстрый пул соединений» — тем более надувательство.
и тогда заголовок статьи про «самый быстрый пул соединений» — тем более надувательство.


Ну на момент написания статьи Вашего кода даже не было в репозитории. Так что — нет. Не надувательство.
А может, эта статья — постановочный заход к публикации Андреем one-datasource?!
Автор хикари ответил Вам. И утверждает что одноклассники в 8 раз медленее, а не быстрее. К сожалению у меня нету приглоса, так что вот ответ github.com/brettwooldridge/HikariCP/issues/464#issuecomment-149141231
Как говорится, бывает ложь, большая ложь, и бенчмарки :) Всегда можно написать бенчмарк, который «докажет» что угодно, если не понимать, что именно он измеряет. А в случае с пулами, очевидно, запустив пустой getConnection() в 8 потоках, автор измерил стоимость contended блокировки. Очень полезно. Особенно, когда в продакшне даже при 5000 запросах в секунду у нас contention наблюдается в < 0.5% случаев. Хотя uncontended случай, на котором one-datasource оказался внезапно быстрее, куда ближе к реальности, на самом деле, и он абсолютно бесполезен, покуда в жизни приложение обычно занимается запросами к базе, а не синхронизацией на пуле.

Окей, пускай даже автор сэкономил 500 наносекунд на доставании коннекшна из пула, и тут же потерял целую миллисекунду (в 2000 раз больше!) на валидации этого коннекшна. То, что товарищ назвал недостатком one-datasource, на самом деле сделано специально: мы целенаправлено избавились от валидации, заменив её ретраями уровнем выше, чтобы в два раза сократить количество запросов к базе и значительно снизить latency.

Забавно, что автор Hikari указывает на наши якобы проблемы с транзакциями. При том, что его пул не поддерживает работу с TransactionManager в принципе! Т.е. вообще не работает! Если приглядеться, все озвученные «проблемы» — это неправильное использование DataSourceImpl. one-datasource используется только внутри наших проектов в контролируемом контексте. У нас нет планов делать из него open source продукт и, тем более, мериться с кем-либо. Я его выложил на GitHub, только чтобы показать несостоятельность бенчмарка.
Автор хикари так же провел бенчмарк if vs try-catch на Java 7 и Java 8 и получил совсем странные результаты. Не могли бы тоже прокомментировать?
В аду приготовлен отдельный котёл для тех, кто делает выводы о производительности по одному бенчмарку без какого-либо анализа :) Этот бенчмарк, как зачастую и бывает, жульничает :)

Ничего не скажу про Java 7u60, т.к. под рукой есть только 7u80, который ведёт себя так же, как и Java 8. А что касается Java 8u60, дела обстоят так. В бенчмарке по умолчанию у списка выставлен initialCapacity = 32, но при этом добавляется лишь 15 элементов. Т.е. выхода за пределы массива никогда не происходит. Естественно, JIT это спекулятивно оптимизирует, ставя uncommon trap и выкидывая эту ветку вообще. В итоге оба варианта компилируются одинаково.

Зато, если поставить initialCapacity=14 или меньше, в профиле останется статистика, что исключение выкидывалось, и JIT уже по-честному скомпилирует ветку для расширения массива. При этом результаты для варианта с try-catch окажутся удручающими:

Benchmark               (initCapacity)  (listImpl)   Mode  Cnt      Score     Error   Units
FastListBench.testList              14         new  thrpt    6   6444,598 ± 195,891  ops/ms
FastListBench.testList              14        orig  thrpt    6  18426,890 ± 790,905  ops/ms
FastListBench.testList              15         new  thrpt    6  19122,083 ± 436,809  ops/ms
FastListBench.testList              15        orig  thrpt    6  18567,706 ± 101,215  ops/ms

Впрочем, и такому бенчмарку нельзя верить, потому как реальный сценарий на продакшне может оказаться совсем другим. И не дай бог кто-то вдруг заиспользует List, основанный на try/catch, не для долгоживущих списков, а для типичного сценария «создал-поработал-забыл», где исключения начнут выскакивать часто, и тогда начнётся самое интересное.
А почему JIT не смог в таком простом случае выкинуть лишний range check?

PrintAssembly для add
  0x000000010f02e688: sub    $0x30,%rsp         ;*synchronization entry
                                                ; - com.zaxxer.microbench.FastList2::add@-1 (line 73)

  0x000000010f02e68c: mov    0x20(%rsi),%ebx    ;*getfield elementData
                                                ; - com.zaxxer.microbench.FastList2::add@5 (line 73)

  0x000000010f02e68f: mov    0xc(%r12,%rbx,8),%r11d  ;*arraylength
                                                ; - com.zaxxer.microbench.FastList2::add@8 (line 73)
                                                ; implicit exception: dispatches to 0x000000010f02e7a5
  0x000000010f02e694: mov    0x18(%rsi),%ebp    ;*getfield size
                                                ; - com.zaxxer.microbench.FastList2::add@1 (line 73)

  0x000000010f02e697: cmp    %r11d,%ebp
  0x000000010f02e69a: jge    0x000000010f02e785  ;*if_icmpge
                                                ; - com.zaxxer.microbench.FastList2::add@9 (line 73)

  0x000000010f02e6a0: mov    %ebp,%r8d
  0x000000010f02e6a3: inc    %r8d
  0x000000010f02e6a6: mov    %r8d,0x18(%rsi)    ;*putfield size
                                                ; - com.zaxxer.microbench.FastList2::add@24 (line 74)

  0x000000010f02e6aa: cmp    %r11d,%ebp         ; Лишняя проверка
  0x000000010f02e6ad: jae    0x000000010f02e76d
  0x000000010f02e6b3: mov    0x8(%rdx),%r10d    ; implicit exception: dispatches to 0x000000010f02e7b5

в тему бенчмарков

java 8
Benchmark               (initCapacity)  (listImpl)   Mode  Cnt      Score     Error   Units
FastListBench.testList              32         new  thrpt   18  24669,079 ± 245,068  ops/ms
FastListBench.testList              32        orig  thrpt   18  24275,624 ± 225,616  ops/ms

java 9
Benchmark               (initCapacity)  (listImpl)   Mode  Cnt      Score     Error   Units
FastListBench.testList              32         new  thrpt   18  12797,725 ± 373,708  ops/ms
FastListBench.testList              32        orig  thrpt   18  11771,681 ± 286,235  ops/ms


неужто нас ожидает медленная java? =)

p.s. по асму там перед сохранением в массив пачка магии включая локи или это издержки дебаг версии?
Посмотрел, действительно, в JDK 9 сгенерированный код слегка распух. «Магия» — это G1 барьеры, коими сопровождается каждый апдейт ссылки в хипе. В JDK 9 G1 стал дефолтным коллектором, отсюда и разница. Стало быть, для честного сравнения надо запускать с -XX:+UseParallelGC.

Ещё одно подтверждение тому, что микробенчмарки зачастую измеряют совсем другое, чем хотелось, и без должного анализа смысла не имеют. Если кто-то говорит, «мой код быстрее в 10 раз, я проверил бенчмарком», и при этом даже не смотрит на логи компилятора, не говоря уж об ассемблере, значит, он безбожно врёт :)
На самом деле код автора написан под конкретный юзкейс — складывать стейтменты внутри коннекшна. И тут же, кстати, у меня возникает ощущение, что всё это абсолютно зря. Давайте на обратные числа посмотрим, что оптимизирует сам автор:

ArrayList: 373 нс
Список с if на Java 7u60: 70 нс
Список исключением на Java 7u60: 25 нс

То есть при переходе с ArrayList на if он выигрывает 303 нс на SQL-запрос, а при переходе на исключения — ещё 45 нс. Мне совершенно не верится, что в контексте выполнения целого SQL-запроса и чтения результатов из него даже отказ от ArrayList дал заметный прирост. Не говоря уж про исключение. В относительных цифрах-то смотрится солидно, но в абсолютных как-то не очень.
причем это не объясняет почему так произошло, только предположения о том, что exception работают быстрее.
на практике в случае с if в его тестах сразу отваливается inlining на add(), а уже потом еще и на remove(). как итог тест полностью бесполезен.

на свежих версиях jdk при срабатывании инлайнинга на обоих методах поведение идентичное, но автора это не останавливает =( начинаются споры по поводу использования в проде старых 6 и 7 версий
И тут же, кстати, у меня возникает ощущение, что всё это абсолютно зря.


При этом сами же используете подобные трюки.
Вы не знаете, о чём говорите. В моём случае есть тесты, на которых такой трюк ускоряет производительность в 1000 раз, либо вообще делает рабочим код, который бы иначе упал с OutOfMemory. Скажем, задача вычитать ровно один элемент из сплитератора, который пришёл из неизвестного источника. Создайте такой сплитератор для примера:

Spliterator<Integer> spliterator = Stream.of(1)
               .flatMap(x -> IntStream.range(0, Integer.MAX_VALUE).boxed())
               .spliterator();

Запустите ужасный некрасивый код, похожий на то, что я пишу:

static class MyException extends RuntimeException {} 

try {
    spliterator.forEachRemaining(x -> {
        System.out.println(x);
        throw new MyException();
    });
} catch(MyException ex) { /* ignore */ }

И сравните с официальным красивым, модным и рекомендуемым способом сделать то же самое:

spliterator.tryAdvance(System.out::println);

Никакой JMH вам не потребуется, разницу увидите невооружённым взглядом. Вся красота разбивается о суровую действительность.
Вы не знаете, о чём говорите.


Да. Не знаю. Но я и не делаю отсюда заключений, вроде:

И тут же, кстати, у меня возникает ощущение, что всё это абсолютно зря.
Вы пытаетесь меня убедить, что если вы не разбираетесь в X и не делаете никаких заключений, значит, я не разбираюсь в Y и тоже не должен делать заключений? :-)
=) нет конечно. Вы в праве делать все что хотите.
А Вы можете в тикет ответить на гитхабе? Мне как-то не хочеться постоянно проксировать ответы =).
А и не надо ничего проксировать. Никому от этого лучше не станет.
Ну почему же, вдруг Вы укажете на некую лже-оптимизацию и это ускорит хикари. Все пользователи от этого выиграют.
Вас спросили что не так с 35 инструкциями, конкретно, и почему это — ерунда?
Потому что это вовсе не лимит инлайнинга. Это значение регулируется параметром JVM (-XX:MaxInlineSize=N) и по-умолчанию оно 35 байт.
это вовсе не лимит инлайнинга


А что же?
Потому что лимит задаётся совсем другими параметрами JVM. HotSpot JVM может инлайнить методы гораздо длиннее 35 байткодов. Смотрите FreqInlineSize.

Если всё ещё не убедительно, проверьте сами.
Заодно и развеем миф invokestatic vs. invokevirtual:

Benchmark                     Mode  Cnt    Score   Error   Units
Inlining.inlineStaticSmall   thrpt    5  298,373 ± 5,752  ops/us
Inlining.inlineVirtualLarge  thrpt    5  298,515 ± 9,902  ops/us

Или запустите с -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining:

    @ 16   bench.Inlining::inlineStaticSmall (4 bytes)
      @ 0   bench.Inlining::smallMethod (25 bytes)   inline (hot)

    @ 16   bench.Inlining::inlineVirtualLarge (5 bytes)
      @ 1   bench.Inlining::largeMethod (109 bytes)   inline (hot)
лимит задаётся совсем другими параметрами JVM

Так в статье и не про это. Просто мимоходом упоминается, что есть вот такая штука длина метода в байткодах для инлайнинга, дефолтная она 35 байткодов. Может Вас смутило слово «лимит»? Окей извиняюсь за плохой перевод.

Заодно и развеем миф invokestatic vs. invokevirtual:

А в статье не говорится что вызов invokestatic быстрее invokevirtual. Там говорится, что у JIT большей вохможностей по оптимизации в случае invokestatic.
длина метода в байткодах для инлайнинга, дефолтная она 35 байткодов
Это называется «слышал звон, да не знает, где он». Есть параметр JVM MaxInlineSize=35, но он означает совсем не то, что думает автор. Это лишь некая эвристика для инлайнинга, и она не мешает заинлайниться и более длинному методу, если JIT сочтёт нужным. Попытки «помочь» JIT-компилятору могут привести ровно к обратному эффекту. Метод checkException не листовой. Принудительно заинлайнив его, автор, например, рискует лишиться инлайнинга вложенных методов, тем самым получив вместо одного вызова два или три.

Там говорится, что у JIT больше возможностей по оптимизации в случае invokestatic.
А это тоже неправда. Вот, навскидку, ровно противоположный пример.

А уж чего стоит аргумент про уменьшение стека с 5 до 4 элементов! С таким же успехом можно сказать, что программа будет работать быстрее и занимать меньше памяти, если названия всех переменных сократить до 1-2 букв :)
Ок, спасибо за развернутый ответ. Думаю автор просто не усложнял в контексте той статьи.
Дело не в том, что автор «не усложнял», а в том, что он просто неправ. По факту MaxInlineSize не играет никакой роли для горячего кода. Утверждение «Наверное ни для кого уже не секрет, что лимит инлайнинга в Hostpot JVM — 35 байткод инструкций» — абсолютная ложь, а не просто «упрощение». И попытки вогнать метод в 34 байта байткода бессмысленны. В контексте статьи автор как раз усложнил себе жизнь, делая бессмысленные операции. Если оптимизировать инлайнинг, надо не гадать, а хотя бы посмотреть, что реально инлайнится, а что — нет. Для этого есть опция +PrintInlining. Про неё же ни слова в статье.
Про неё же ни слова в статье.


Потому что статья не про инлайнинг. А про то, что делал автор, чтобы создать быстрое решение. Нету смысла описывать детали работы инлайнинга, если цель просто описать подходы, что применялись. Иначе надо было бы писать десятки постов.
Не понял. Что значит, статья не про инлайнинг? Я вижу три экрана про инлайнинг, начиная с заголовка «Down the Rabbit Hole». Почти добрая половина статьи. Окей, я тогда скажу, что подходы неверные. Или вы ответите, что статья не про подходы? :-)
Почти добрая половина статьи


Просто кода много =).

Окей, я тогда скажу, что подходы неверные.


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

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


Это делаете Вы приводя ложную аналогию. Представьте, миллиардера спросили, как ему удалось стать миллардером, он ответил, что долго и упорно работал и это помогло ему стать миллиардером. Вы же утверждаете, что этот труд не помог есть стать миллардером, а причина в молитве макаронному монстру.

Конкретные примеры вам Андрей Паньгин разъяснил, тут вроде бы нечего добавить.

Андрей привел пример FastList.add() утверждая, что такого рода оптимизация — это скорее деоптимизация. Пока из их раговора я не понял, кто же прав.
Вы же утверждаете, что этот труд не помог есть стать миллардером, а причина в молитве макаронному монстру

делать выводы на основе байткода совершенно неверно, то что в некоторых случаях это сработало, закрепляет неправильные предложения и в итоге уводят в совершенно непонятных направлениях с постепенным превращением всего этого в cargo культ. посмотрите на статью автора с его манипуляциями байткодом с пачкой необоснованных утверждение и статьи Шипилева или Томпсона, разница гигантская, так как у них идет разбор на уровне asm и иногда железа, что же у нас происходит на самом деле.

Пока из их раговора я не понял, кто же прав.

прав некорректный бенчмарк:
1) автор сравнивает не просто add(), но и тут же remove(), что вносит дополнительную погрешность
2) автор утверждает, что методы add() имеют минимальные отличия, на практике в случае if в его тесте метод add() не инлайнится, а идет явный вызов
3) автор утверждает, что методы remove() полностью идентичны, на практике в случае if в его тесте метод remove() не инлайнится (предположительно предыдущий add() сломал оптимизации последующие), а идет явный вызов

по итогу:
1) метод с exception идет линейно, без дополнительных вызовов, к тому же нету случая когда этот exception выбрасывается
2) метод с if сразу производит 15 вызовов функции add() и следом 15 вызовов remove().

что мы вообще меряем? стоимость 30 вызовов функций? логично что вызывать их будет дороже, так как переходы не бесплатны и заметно дороже линейного выполнения кода
первый же раздел Down the Rabbit Hole

Мы изучали скомпилированный байткод для каждого метода и даже изменяли методы так, чтобы они попадали под лимит инлайнинга

Иногда, видя что метод превышает лимит инлайнинга, мы думали о том как изменить его таким образом, чтобы избавится от нескольких байт-инструкций. Например:

Наверное ни для кого уже не секрет, что лимит инлайнинга в Hostpot JVM — 35 байткод инструкций. Поэтому мы уделили некоторое внимание этому методу, чтобы сократить его и изменили его следующим образом:

Получилось довольно близко к лимиту, но все еще 36 инструкций. Поэтому мы сделали так:

Выглядит проще. Неправда ли? На самом деле, этот код хуже предыдущего — 45 инструкций.

Как раз ниже лимита в 35 байткод инструкций. Это маленький метод и на самом деле даже не высоконагруженный, но идею Вы поняли.


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

Общения в github, где автор на основе идентичности методов утверждает, что в его тесте они тоже работают одинаково радует. так же как и желания тестировать только на старых версиях jvm, которые работают не всегда корректно.
>> Для этого есть опция +PrintInlining

данная опция на версиях jvm, что использует автор крешит jvm на его бенчмарках. А так да, основная масса выводов автором сделана на основе анализа байткода, без самого анализа что же у нас происходит в реале
Зато я нашёл в исходниках ещё одну замечательную «оптимизацию» :)

      try {
         elementData[size++] = element;
      }
      catch (ArrayIndexOutOfBoundsException e) {
         // overflow-conscious code
         final int oldCapacity = elementData.length;
         final int newCapacity = oldCapacity << 1;
         @SuppressWarnings("unchecked")
         final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity);
         System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);
         newElementData[size - 1] = element;
         elementData = newElementData;
      }

Почему это не оптимизация, а совсем наоборот, я рассказывал на JPoint в презентации про устройство виртуальной машины HotSpot.
С одной стороны Вы правы. С другой — вполне допускаю, что за время жизни пула исключение бросится несколько раз. В то время как add/remove будут происходить постоянно. И в долгосрочной перспективе, такая оптимизая выгодней «If».
Так а в чём здесь оптимизация, поясните?
Ну я так понял, что цель всей той колбасы просто избежать условия
if (size < elements.length)

Вообще я задал вопрос автору. Так что подождем. Я так не оптимизирую, если что =).
Избежать условия не получится. В принципе. По ссылке выше рассказано, почему.
Из ссылки выше:

if (index >= arr.length) {
break;
}


Речь об этом условии. Я так понимаю что автор Хикари избегает его. Так как выбрасывание эксепшена за жизнь пула происходит раз-два и все.
А как, по-вашему, JVM понимает, что пора выкинуть exception, не проверяя условия?
Я не говорил, что не JVM проверяет диапозоны массива.
try сам по себе дорогой. Я почти уверен что намного дороже if.
Вы ж не думаете что исключения дорогие только когда кидаются. Нужна ведь инфраструктура которая их ловит.
Стоиомсть try не важна, если пул живет месяцами и за этот месяц try вызывается пару раз для увеличения списка. В то время как add/remove выполняются каждую секунду сотни раз в случае нагруженности пула. Но это лишь мое предположение.
я себе написал StringBuilder с аналогичной оптимизацией, если создавать новый билдер каждый раз, то он на порядок медленнее дефолтного, но если переиспользовать сущействующий, чтобы массив расширился до некоторого максимально значения только один раз, то такая оптимизация дает выигрыш примерно в 30%
JVM и так отлично оптимизирует StringBuilder.

String s = «aaa...»; //100500 chars
new StringBuilder().append(«1»).append(s).toString();


компилятор заоптимайзит в new char[1+s.length]. Опция — OptimizeStringConcat. Так что прирост очень сомнителен.
в таком простом варианте, наверно, да, заоптимизирует… но в моем случае — есть бенчмарки, я вижу какой вариант быстрее
Давайте бенчмарки. А вдруг там ошибка =)?
I benchmarked both ways when the code was written. This is faster 95% of the time. It only incurs overhead when the list is expanded — but that is a slow path anyway because of the memory copy.


github.com/brettwooldridge/HikariCP/issues/462
Как я понял, это отсюда код. У меня в другом месте facepalm ещё случился: ну зачем же ArrayList-то расширять? Мало граблей на этом собрали? Если в девятке вдруг во все листы добавят новый метод (скажем, parallelSort), и у ArrayList будет оптимизированная реализация, в данном классе он будет молча ничего не делать. Можно будет хвастаться, что FastList нереально быстро сортирует в параллель :-) Неужели мало граблей на этом в восьмёрке собрали? Что плохого в том, чтобы AbstractList наследовать?
Я, кстати, нагрешил тут недавно в своей либе — использую кастомное исключение для control flow. В этом плане очень помог конструктор Error(null, null, false, false), который в несколько раз ускоряет создание исключения. Наблюдаю константную потерю на выкидывании где-то 200-300 наносекунд (против примерно 1500±длина стектрейса при обычном исключении). В моём случае эта константная потеря окупается, потому что альтернативный вариант без исключения затормаживает даже на не очень больших объёмах данных (только на совсем маленьких входных данных наблюдается проигрыш при использовании исключения).
потому что альтернативный вариант без исключения затормаживает


Речь о
if (condition) return error_core;

?

И что за библиотека такая, где надо волноваться о таких мелочах?
Не в упрек автору данной темы.
Не поленился, сходил на github проекта. Посмотрел код. Я в шоке.
Тут рассказывают о том, как удалось сократить количество JVM инструкций с 35 до 34, забывая про генерацию кода с помощью javassist.
Может кто-то объяснит доходчиво, как динамическое создание класса, с помощью javassist ускоряет работу 34 инструкций перед 35 инструкциями.
как динамическое создание класса, с помощью javassist ускоряет работу 34 инструкций перед 35 инструкциями.


А как эти 2 вещи вообще связаны =)?
Я не сильно разбираюсь в оптимизации JIT. Разве генерация дополнительного кода не вносит затраты на его исполнение?
Уточню вопрос. Дело в том, что система генерирует байт код для каждого нового DataSource, используя старый код только в виде шаблона.

У меня вопрос. Этот самый пул соединений, он стоит поверх JDBC пула.
Какова производительность этого пула при достижении максимума соединений или запросов в базовом пуле?
Имеется в виду, что остановка некоторых потоков в режиме ожидания новых ресурсов, не влияет на производительность других потоков.
Ведь там используется не честная блокировка (первый запросил, первый получил).

Еще один вопрос можно? Как данный пул можно использовать, скажем в WildFly с исходным XADataSource?
Все это оч мило и приятно конечно — простым прописыванием library depndency получить «самый быстрый connection pool». Но, если кто-то по производительности уперся в переиспользование(!) коннектов в пуле(!), то я уже искренне бы поздравил этих людей. Да и скорее всего у них наверняка уже написан свой аналог Hikari.
Используем HikariCP уже два года в нашем проекте. Прирост в производителъности ноль. Единственая разница с предыдущим пулом (c3p0) в том, что HikariCP активно развивается.
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории