Читать в телеге. Когда-то там были посты не только от меня.
Семантики памяти java
Неплохой, хоть и весьма специфичный доклад про то, какие есть варианты семантик в java, кроме happens-before: plain, opaque, acquire-release. В основном они нужны в случаях, когда гарантии от volatile
слишком сильные, и за счет использования более слабых семантик можно получить прирост производительности. Ну или если вы хотите унизить кого-нибудь на собесе, кто вам задает вопросы про многопоточность для вакансии перекладывателя json-ов.
В докладе обсуждается, что такое семантика вообще, кратко повторяется база, и показано иерархическое различие разных семантик. Ко всему есть наглядные примеры.
Вообще в этом контексте вспоминается более фундаментальная статья про модели памяти, о которой я писал ранее.
Вызов C++ из питона
Оказывается, кроме ctypes и Cython с тех пор как я смотрел появился еще один способ, pybind11 (если не считать всякие граали).
Но во всех трех подходах надо че-то думать: в ctypes надо код в динамическую библиотеку запихнуть, а потом ее еще и загрузить; в Cython надо немного поприседать с изменением исходников и типизацией; в pybind11 — писать экспорты.
Отрыл cppyy. В нем чтобы импортировать C++ класс достаточно написать
cppyy.include("someClass.cpp")
instance = cppyy.gbl.SomeClass()
… и все. Методы и классы легко грузятся по имени. Работает это все за счет cling — интерпретатора для C++. Можно грабить корованы создавать экземпляры стандартных классов, например, vector.
Разумеется, цена этому — производительность, но питон же, да и то, не все так просто.
Сравнение LLM
Занятное сравнение LLM. При этом методика очень простая: задать несколько вопросов чат ботам и сравнить ответы.
Меня порадовала задачка:
Sally (a girl) has 3 brothers. Each brother has 2 sisters. How many sisters does Sally have? Let’s think step by step.
Правильный ответ почти ни одна модель не смогла родить.
No data в Grafana
Некоторое время назад наткнулся на довольно противный баг в графане: добавил дашборд, вижу данные, потом меняю интервал на более продолжительный… и графики исчезают, вместо них вижу “No data”.
Сначала грешил на комбинацию нестандарного способа запихивания данных и кэширование, с которым вроде не все так просто в этом Mimir (ссылки потерял, поверьте, вы все равно не хотите это знать). Но реальность оказалась еще хуже: все данные на месте, просто… не запрашиваются.
Количество точек в запросе для отображения графика зависит от размера окна (sic!). Если быть точнее, то от ширины панели. При запросе к Prometheus вычисляются значения для точек start
, start+interval
, start+2*interval
, … end
. interval
— это период времени, деленный на количество точек. Если значения для какой-то точки нет, то Prometheus возвращает самое новое значение из предыдущих, но только если оно не старше какого-то периода (иначе метрика считается без данных, если она не обновлялась). У меня метрики отсылались 3 раза в день, вот и получалось, что данные просто “не находились”. Я это полечил костылем, выставив Max data points = 11000
(больше нельзя) и Min interval = 30m
в настройках запроса.
Вроде как у каждого шага есть обоснование, почему это должно быть так, и в типичном сценарии, когда метрики опрашиваются каждые 5 секунд, все будет работать из коробки, но епрст… Мне даже официальная поддержка ответила копипастой отсюда, официального и подробного туториала я по этой теме не смог быстро найти. И вообще, совсем не ожидал, что так сложно будет нарисовать график по точкам…
Компилируемые и интерпретируемые языки
Перебросили мне тут вопрос про эту классификацию. Первая мысль — “ну это же очевидно”: компилируемые компилируются, например C++, а интерпретируемые построчно исполняются, например питон! Но потом появляется какой-нибудь .pyc
файл — скомпилированный байт-код. И возникают вопросики — а чем это от java тогда отличается (ведь там тоже байт-код)?
А потом можно вспомнить про существование REPL почти для каждого современного языка и простая классификация вообще сыплется. Ошибочно говорить “язык компилируемый”, более корректно говорить “Y реализация языка X имеет компилятор”. Еще одна сложность — это JIT. Вроде как компилирует, но во время исполнения уже… А если машинный код программы запускается на эмуляторе или в виртуалке — можно ли считать ее по-настоящему скомпилированной?
Вообще, если посмотреть википедию про интерпретаторы, то там будет JVM.
И компилятор, и интерпретатор производят практически одни и те же операции, чтобы в итоге получить из исходного кода машинный. Как у многих классификаций, четкой границы тут нет, скорее спектр вариантов. В википедийной статье достаточно разносторонне рассмотрен этот вопрос: процесс разработки (надо ли ждать компиляции), развертывания (build once run everywhere), производительности и т.п. А еще можно погрузиться в шаблонные интерпретаторы, микрокод и т.д.
Так что я бы сказал, что разделять языки на “компилируемые” и “интерпретируемые” занятие неблагодарное и даже немного вредное. В конечном счете почти любая программа компилируется (транслируется из одного языка в другой), а потом интерпретируется (исполняется).
Стоимость боксинга в Scala
Отличная статья с бенчмарками. Для справки: боксинг — это замена примитивного типа (int
) на ссылочный (Integer
) или, в более общем случае, просто увеличение уровня косвенности (когда чтобы добраться до “настоящего” значения нужно больше ссылок).
TLDR:
- Стоимость боксинга зависит от JVM и оптимизаций.
- Opaque-типы почти бесплатны
- ФП-стиль “дороже” императивного при использовании OpenJDK.
- Боксинг довольно хорошо оптимизируется в GraalVM, с ее использованием почти нет разницы, в каком стиле писать.
Почти всё, что надо знать знать про кодировки
Отличный доклад, в котором рассказана основная история вопроса от первого телеграфа до UTF, а также освещены основные моменты про управляющие символы, диакритику, виды нормализации, UTF-16 vs UTF-8, эмодзи, флаги и т.п. Подано хорошо и с юмором, рекомендуется к просмотру детям программистам всех возрастов.
PRQL
SQL — это sequel, а PRQL — это prequel. Как и положено, второй появился позже первого и эксплуатирует его наследие:)
Довольно занятная штука. Писать что-то длинное в SQL не очень удобно из-за неестественного порядка записи — это как на питоне пробовать в функциональном стиле писать с filter
и map
(хотя можно привыкнуть). PQRL нацелен решить эту проблему и подобно тому, как TypeScript транслируется в JS, может быть транслирован в обычный SQL. Его даже в ClickHouse добавили.
Я немного попробовал PRQL в песочнице — не могу сказать, что это “вау”, но стоит попробовать. Правда сомневаюсь, что что-то совсем зубодробительное получится написать существенно проще чем в обычном SQL. Ну и разумеется, использовать это стоит только для “ручных” запросов, потому что так-то основную работу делают ORM ну или на крайний случай DSL.
Варианты реализации совместимости типов
Статические системы типов можно условно поделить на два вида: номинативные и структурные. В номинативных системах совместимость и равенство типов определяется по имени. Классический пример — java. Вот есть два класса:
class Duck {
String quackSound;
void quack();
}
class Quaker {
String quackSound;
void quack();
}
С точки зрения java — это два разных типа: имя разное, и пофиг, что начинка одинаковая. А вот в структурной системе типов это будет считаться одинаковым типом как раз потому что структура одинаковая. Структурную систему типов имеет TypeScript и этим он достаточно сильно отличается от других “мейнстримовых” языков. Джависты в шоке от того, что можно делать с помощью TypeScript, а кто-то даже предложил на нем тесты писать для java-проекта (sic!).
Еще есть утиная типизация — ее типы вообще не заботят, а только поведение. Вот такой класс
class McDuck {
Int wealth;
void quack();
}
ни по имени, ни по структуре не совпадает ни с одним из предыдущих. Но в Python все три класса будут совместимы, если от них нужен только quack
.
Разумеется, почти все практические языки не на 100% строги. В какой-нибудь Scala вполне спокойно можно организовать структурную типизацию.
SSH как SOCKS-proxy
Чтобы быстро и без проблем скачать что-то из заблокированного интернета не надо ставить VPN и WireGuard, не надо форвардить порты, нужно всего лишь… читать далее
ssh -D 8080 -C -q -N name@server
...
curl -s -x socks5h://0:8080 https://some.shit/file