Comments 26
Извините за возможно тупой вопрос, но GPU это graphics processing unit? Какого рода задачи выполняет ваше приложение, если оно одновременно и использует мейнстримный спринг бут и такую экзотику как вычисления на GPU?
public enum TestEnum {
A("1"),
B("2"),
C("3"),
D("4"),
E("5"),
F("6"),
G("7");
private String number;
private TestEnum(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
}
В перечислениях в Java есть встроенное поле ordinal
, представляющее порядковый номер члена перечисления.
На который лучше не завязываться, т.к. кто-нибудь воткнёт новую константу между существующими и вся бизнес-логика посыплется, хотя никаких исключений может и не быть.
Частично соглашусь, правда, это зависит от ситуации. Например, если вы перечисляете месяцы или дни недели, то никто уже туда ничего не добавит, это во-первых. Во-вторых, по-православному добавление новых постоянных всегда делается в конец существующего энума. На это завязана в частности реализация соотношения перечислений в JPA: по-умолчанию в таблицу вставляется именно порядковый номер, а не имя, т. к. предполагается, что порядок самих элементов перечисления остаётся постоянным.
Во-вторых, по-православному добавление новых постоянных всегда делается в конец существующего энума.
Это как пиратский кодекс (свод указаний, а не жёстких законов). И, честно говоря, я ни разу не видел, чтобы этим руководствовались постоянно, без каких-либо к тому принуждений. Например, тесты, которые проверяют порядковый номер каждой константы.
по-умолчанию в таблицу вставляется именно порядковый номер, а не имя
Все делают ошибки, а принятые плохие решения, просочившись в стандарт, остаются там навсегда. Это такой же косяк, с которым приходится жить, как и @*ToMany(fetch = EAGER).
В том-то и дело, что это не ошибка. Да, разработчики JDK не прописали жёсткого запрета на перестановку членов перечисления, но уже тот факт, что Enum
можно сериализовать (а вместе с ним и EnumSet
/EnumMap
, в которых в частности используется ordinal
) говорит о том, что перестановки делать нельзя. В JPA исходя из этого и решили использовать порядковый номер, а не имя. Во-первых, чтобы повторить исходное поведение (старые данные будут неверно преобразовываться в случае смены порядка), и во-вторых чтобы использовать число вместо текста в таблице.
Ну, не знаю, не знаю. Как по мне, так ошибка самая что ни на есть.
Впрочем, сугубо внутренний, относящийся к деталям реализации, инфраструктурныйordinal()
в публичном доступе тоже, по-моему, не есть хорошо.
Использование данного метода в прикладном функционале сродни использованию java.util.ArrayList#trimToSize
: метод, несомненно, полезный, но в 99,(9)% неиспользуемый вне реализации стандартной библиотеки классов. Но он не мешает, т.к. работа с коллекциями в подавляющем большинстве случаев идёт на уровне интерфейсов.
Приведу ещё пару примеров решений, на первый взгляд ошибочных, но на деле оказавшихся очень даже полезными.
1) Несериализуемый Optional
в своё время вызвал немало споров, а всё потому, что значительная часть пользователей не поняла, что Optional
задумывался как OptionalReturn
, иными словами он должен использоваться только как возвращаемое значение и с этой точки зрения запрет сериализации выглядит полностью логичным и оправданным.
2) Одноразовый Stream
тоже вызвал недоумение у многих, привыкших переиспользовать коллекции и вертеть их как угодно, тем более, что Stream
намного тяжелее и дороже коллекций. Но оказывается, что для ленивого связывания и параллелизма очень сложно реализовать механизм поддержания и сбрасывания промежуточного состояния. И ещё сложнее реализовать все свойства стримов в случае, например, построчного чтения из файла.
С перечислениями, на мой взгляд, та же история, просто по непонятной причине это явно не прописали в документации.
>> но уже тот факт, что Enum можно сериализовать (а вместе с ним и EnumSet/EnumMap, в которых в частности используется ordinal)
То что ordinal используется для быстрой работы enum set/map, не говорит что ordinal используется для сериализации (можете сами в этом убедиться).
>> В JPA исходя из этого и решили использовать порядковый номер, а не имя.
Не факт, что именно из-за этого. Как по мне странное решение, я думаю не стоило делать default value вообще (пусть программист подумает хорошо). Лично я стараюсь использовать сокращенные мнемоники (в виде отдельного поля в enum и реализации javax.persistenceюConverter) если сохранении полного enum name не желательно из-за производительности. Просто если базой пользуется еще кто-то (а не только ваш jpa код), то эти кто-то будут очень вам "благодарны", что вы все циферками записали/засекретили, смысл которых нужно помнить или искать в ваших java сырцах ))
>> разработчики JDK не прописали жёсткого запрета на перестановку членов перечисления
Если enum не сохраняется по индексу (в проектах, где я участвовал мы никогда так не делали) нет смысла добавлять новый enum в конец. Добавление же нового элемента в более логичную позицию улучшает читабельность кода (группирая похожие элементы вместе, а не разнося их)
Это не пример из прода) Тут суть в том что есть некая строка которая возвращается) А не в номере.
@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])
//Выпиливаем все не нужные.
Более правильным будет выпиливание ненужных библиотек из classpath-а приложение, а то, что нужно явно исключить лучше описывать в application.{yml|properties}
:
spring.autoconfigure.exclude= \
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, \
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, \
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
Это во-первых позволяет отвязать настройки от кода, а во-вторых создав несколько файлов настроек под соответствующий профиль можно легко переключаться между ними.
Ещё стоит оптимизировать приложения по области их деятельности:
Должно выживать под большой нагрузкой => поднимаем фоновый процесс + пулинг модель, убираем сериализацию, переходим на Webflux (если есть возможность), включаем http/2 и.т.д.
Должно обрабатывать большие массивы данных => вспоминаем про спец. инструменты хранилищ данных, буфферные чтения, воскрешаем SAX парсеры и п.р.
И что ни одного квадратного алгоритма у себя не нашли? Обычно одна такая найденная и поправленная штука в хорошем месте перекрывает по эффекту примерно все перечисленное в статье, разве что кроме тяжелого шифрования в ненужном месте.
Добавить свободных ресурсов и скорости может ещё отказ от Spring в проекте. Не прорабатывали этот вариант?
100 % правда. Был проделан большой анализ. Рассматривали micronaut, quarqus и "свое решение". Micronaut по метрикам мало оптимизаций привносит. Quarqus 2.0 много времени на переписывание и поддержку, оставили за ним только момент с высоконагруженнымы микросервисами, но даже в нем нету решения главного бича спринга.
Наибольшей оптимизации спринга можно добиться если делать все возможные генерации в precompile, то-есть отказаться от спринга. Тогда тут можно выиграть не плохо ресурсов и RPS. Но появится другая проблема: интеграция с другими сервисами(redis, elastic и т.д.), когда в спринге ты просто можешь прикрутить стартер и все готово.
Готовых хороших решений нету, особенно с мно-вом интеграций с другими сервисами и большого комьюнити.
Micronaut по метрикам мало оптимизаций привносит
Наибольшей оптимизации спринга можно добиться если делать все возможные генерации в precompile
Но погодите, ведь микронавт ровно этим и занимается. DI, декорация, проксирование и прочее выполняется в compile time, насколько я понимаю. Какие именно метрики вам не понравились?
Кажется что это тема для отдельной статьи.
Действительно какие-то вещи он делает в compile time. Тот-же DI, он другой и делается в compile time и решает проблему с рефлексией в спринге, но quarqus представляет более оптимизированное решение. Некоторые вещи он продолжает делать в runtime, тот-же AOP - частичная компиляция. Так как micronaut пытается быть таким-же как Spring, но "лучше", из-за этого он тащит ряд похожих решений спринга.
После проделанных тестов на производительность, у нас отпали вопросы к micronaut. Micronaut производительнее чем Spring. Но не так значительно чтобы отказаться от Spring. Quarqus выглядит намного вкуснее.
то внутренние операции в StreamApi на небольших массивах все равно используют слишком много времени выполнение по сранению со StreamApi.
Вроде как описка.
Можно, пожалуйста, чуть подробнее про, тк вроде все @Componentиндексированы в спринге :
Если мы используем Spring, индексируем его компоненты с помощью spring-indexes, что даст прирост скорости запуска
Юнга, стоп, у нас кончились ресурсы. Или как мы оптимизировали наши микросервисы