Есть даже варианты с уже подключенной камерой: ESP32-CAM
Качество не сказать, чтобы супер. Но для технических нужды хватает за глаза (брал для слежения за 3D принтером, когда из дома отлучиться надо).
Интересно, а можно ли использовать рекорды в качестве параметров аннотаций? А то ограничение только скалярами, строками и классами нередко оказывается слишком неудобным.
Вот давайте ещё раз заглянем под спойлер с реализацией метода ConcurrentHashMap.computeIfAbsent. результат возвращается из переменной val. Где происходит присвоение в эту переменную? В 6-и местах. Я их там даже специально пометил. Хоть пометки и не очень заметными вышли, т.к. код очень разлапистый. Первое присвоение не под блокировкой. Но там просто присваивается null. А вот все остальные места — под блоками synchronized. Т.е. нет ни одного пути выполнения, который не попадал бы на блокировку. Ну кроме случая с пустой коллекцией.
Более того. Данные в нашем случае из этой коллекции вообще не удаляются. Никогда. И там используется сравнительно небольшое количество ключей. И именно это сыграло дурную шутку, т.к. в случае большого количества ключей блокировки бы размазывались по разным объектам нод и там неполучалось бы такого контеншена.
Всё строится на так называемых неблокирующих алгоритмах, основывающихся на том факте, что Java даёт определённые гарантии по работе с памятью. Особенно с общей памятью в многопоточной обработке.
Если приводить максимально простой пример, то, например, можно вместо честной блокировки завести флаг в виде AtomicBoolean и перед входом в критическую секцию делать магию:
private static AtomicBoolean guard = new AtomicBoolean(false);
public void doSometing() {
if (guard.compareAndSet(false, true)) {
try {
// It's safe now. We can change the state.
} finally {
guard.set(false);
}
} else {
// Do something non-destructive.
}
}
Это намного дешевле, чем честная блокировка и во многих применения этого достаточно. Даже в штатной библиотеке JRE эти подходы используются очень широко.
and must not attempt to update any other mappings of this map.
Но другой маппинг и не модифицируется. Более того, после некоторого прогрева там начинается только чтение без модификаций. Но при этом картина в профиле не меняется к лучшему.
Более того чуть выше:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple
Т.е. контекст указанной вами строки относится именно к ситуации, когда требуется вычисление лямды с новым результатом, а не чтение. Блокировка на чтение контр интуитивна в данном случае.
Так-то есть, но любая имплементация — компромисс. Да и ConcurrentHashMap в целом очень хороша. Сделать многопоточную реализацию лучше весьма проблематично. За вот таким вот исключением...
Очень рад это слышать. Есть где проголосовать за фичу, или это пока только на словах обсуждалось? ;)
А я правильно понимаю, что раз планируются все платформы, то можно и на потдержку GLSL надеяться, или как там у UE с шейдеоами под Linux устроено?
Хм… И правда ларчик просто открывался. Спасибо!
Огромное спасибо за статью!
Интересно, а насколько сложно сделать эстиматор из последнего примера надёжным?
Есть даже варианты с уже подключенной камерой: ESP32-CAM
Качество не сказать, чтобы супер. Но для технических нужды хватает за глаза (брал для слежения за 3D принтером, когда из дома отлучиться надо).
И как быть с отказоустойчивостью? pgbouncer обычно не от хорошей жизни ставят, а чтобы надёжность повысить.
Ну в случае с GraalVM, таки долгий прогрев имеет место быть. Причём сильно дольше, чем у хотспота.
В профильном чатике телеграмма много экспериментировали на эту тему. В некоторых тестах прогрев получался в разы дольше хотспотовского.
А вот это уже действительно интересно...
На самом деле, что в Git, что в Mercurial, с кодировкой имён файлов под Windows всегда были проблемы.
Простой опыт. Попробуйте закоммитить файлы под Windows, а потом склонировать на Linux. Или в обратную сторону. Все не LATIN символы будут покорёжены.
Так что если над проектом работают люди из разных OS, то только английская кодировка. Увы...
Интересно, а можно ли использовать рекорды в качестве параметров аннотаций? А то ограничение только скалярами, строками и классами нередко оказывается слишком неудобным.
Да-да. Благодаря vkovalchuk уже разобрались. И даже UPD2 уже написан по этому поводу.
Так что актуальность статьи остаётся только для Java 8 и тех страдальцев, кто пока не может с неё спрыгнуть.
Хм… Да. Вы меня поймали!
Надо исправлять.
Я тоже так думал.
Вот давайте ещё раз заглянем под спойлер с реализацией метода ConcurrentHashMap.computeIfAbsent. результат возвращается из переменной val. Где происходит присвоение в эту переменную? В 6-и местах. Я их там даже специально пометил. Хоть пометки и не очень заметными вышли, т.к. код очень разлапистый. Первое присвоение не под блокировкой. Но там просто присваивается null. А вот все остальные места — под блоками synchronized. Т.е. нет ни одного пути выполнения, который не попадал бы на блокировку. Ну кроме случая с пустой коллекцией.
Более того. Данные в нашем случае из этой коллекции вообще не удаляются. Никогда. И там используется сравнительно небольшое количество ключей. И именно это сыграло дурную шутку, т.к. в случае большого количества ключей блокировки бы размазывались по разным объектам нод и там неполучалось бы такого контеншена.
Хороший вопрос, достойный отдельной статьи.
Всё строится на так называемых неблокирующих алгоритмах, основывающихся на том факте, что Java даёт определённые гарантии по работе с памятью. Особенно с общей памятью в многопоточной обработке.
Если приводить максимально простой пример, то, например, можно вместо честной блокировки завести флаг в виде AtomicBoolean и перед входом в критическую секцию делать магию:
Это намного дешевле, чем честная блокировка и во многих применения этого достаточно. Даже в штатной библиотеке JRE эти подходы используются очень широко.
Понял. Согласен. На скриншоте как раз профиль того момента, когда я обнаружил проблему. Т.е. на Java 8.
В дальнейшем начал копать и понял, что в Java 11 ситуация не изменилась, хотя строки и сдвинулись.
Но другой маппинг и не модифицируется. Более того, после некоторого прогрева там начинается только чтение без модификаций. Но при этом картина в профиле не меняется к лучшему.
Более того чуть выше:
Т.е. контекст указанной вами строки относится именно к ситуации, когда требуется вычисление лямды с новым результатом, а не чтение. Блокировка на чтение контр интуитивна в данном случае.
нетуда
Так-то есть, но любая имплементация — компромисс. Да и ConcurrentHashMap в целом очень хороша. Сделать многопоточную реализацию лучше весьма проблематично. За вот таким вот исключением...
А изначально напоролся на 1.8.0_222
Как ни странно, исходники реализации брал из OpenJDK 11.