В прошлый раз рассказывал про langgraph. а сегодня расскажу о том, почему у меня сгорела дыра из-за него🌚
Дело в том, что langgraph пытается казаться на столько удобным решением, что они даже запилили собственную IDE, и назвали ее langgraph studio (далее lgs). Очень блять оригинально.
Как же выглядит IDE для разработки агентов? Нужно ли там писать код? Можно ли там вайбкодить с помощью агента, которого сам же пишешь? 🤔 Все эти вопросы сразу остро встают на повестке дня.
Но все гораздо прозаичнее (см. картинку). Эта присрачка позволяет запускать каждый узел в графе (функцию) отдельно, мейнтейнить стейт, менять входные параметры. Короче говоря, позволяет всячески эксперементировать с узлами без необходимости работать с полным циклом запрос-ответ. Удобно? Не то слово! Идея просто бомбическая.
Разумеется, наш специально обученный человек сразу захотел lgs использовать. И тут его трудно осуждать.
Сначала все было хорошо. Сплошные востороженные возгласы. Но внезапно мне прилетает тревожное сообщение "В lgs не работает подключение к бд"😱
Начал разбираться в проблеме. Как вы можете помнить, коннекшн к бд я храню в contextvars. Подробнее об этом я писал тут. Когда lgs запускает отдельно ноду, то contextvars пустые. Поэтому и подключения нет. Надо как-то подключиться к бд и положить коннекшн в переменную перед запуском каждой ноды. Изи!
И вот тут меня настигло абсолютное разочарование. Потому что никакого способа это сделать разработчики не предоставили. Ни хуков, ни api для плагинов, вообще ни-ху-я. Просто нет возможности выполнить код в этой IDE помимо кода узла😔
ТО ЕСТЬ, разрабы lgs дали способ работать с каждым узлом изолированно от всего остального кода, но не подумали, что может потребоваться ЧТО-ТО от этого остального кода. Гении ебать!
В общем ключе задача формулируется так: "У библиотеки или тулзы отсутствует нужный api для взаимодействия, а вам позарез надо вмешаться в ее модель выполнения". Звучит конечно так себе. Поэтому добавим "...для разработки или тестирования"😏
Это был пост-затравка. В следующем посте я расскажу, как решал эту проблему в python. Но подобный метод может применяться практически в любых интерпретируемых ЯП. В комментах пишите, как бы вы решали подобную проблему👇
Дело в том, что langgraph пытается казаться на столько удобным решением, что они даже запилили собственную IDE, и назвали ее langgraph studio (далее lgs). Очень блять оригинально.
Как же выглядит IDE для разработки агентов? Нужно ли там писать код? Можно ли там вайбкодить с помощью агента, которого сам же пишешь? 🤔 Все эти вопросы сразу остро встают на повестке дня.
Но все гораздо прозаичнее (см. картинку). Эта присрачка позволяет запускать каждый узел в графе (функцию) отдельно, мейнтейнить стейт, менять входные параметры. Короче говоря, позволяет всячески эксперементировать с узлами без необходимости работать с полным циклом запрос-ответ. Удобно? Не то слово! Идея просто бомбическая.
Разумеется, наш специально обученный человек сразу захотел lgs использовать. И тут его трудно осуждать.
Сначала все было хорошо. Сплошные востороженные возгласы. Но внезапно мне прилетает тревожное сообщение "В lgs не работает подключение к бд"😱
Начал разбираться в проблеме. Как вы можете помнить, коннекшн к бд я храню в contextvars. Подробнее об этом я писал тут. Когда lgs запускает отдельно ноду, то contextvars пустые. Поэтому и подключения нет. Надо как-то подключиться к бд и положить коннекшн в переменную перед запуском каждой ноды. Изи!
И вот тут меня настигло абсолютное разочарование. Потому что никакого способа это сделать разработчики не предоставили. Ни хуков, ни api для плагинов, вообще ни-ху-я. Просто нет возможности выполнить код в этой IDE помимо кода узла😔
ТО ЕСТЬ, разрабы lgs дали способ работать с каждым узлом изолированно от всего остального кода, но не подумали, что может потребоваться ЧТО-ТО от этого остального кода. Гении ебать!
В общем ключе задача формулируется так: "У библиотеки или тулзы отсутствует нужный api для взаимодействия, а вам позарез надо вмешаться в ее модель выполнения". Звучит конечно так себе. Поэтому добавим "...для разработки или тестирования"😏
Это был пост-затравка. В следующем посте я расскажу, как решал эту проблему в python. Но подобный метод может применяться практически в любых интерпретируемых ЯП. В комментах пишите, как бы вы решали подобную проблему👇
❤5
Итак, я обозначил проблему. Вкратце: у нас библиотека или тулза, которая настолько говяная, что к ней не подступиться через публичный api, но недостаточно говяная, чтоб от нее отказываться. А нам позарез надо что-то поменять в ее поведении.
В комментах никто не написал, как бы это делал (эх 😔), поэтому дам ответ сам: monkey patch - это возможность менять код в рантайме.
Как же это выглядит в моем случае. У меня тулза - это вонючий langgraph studio (lgs), и мне надо, чтоб во всем коде, при запуске через lgs было доступно подключение к бд.
Напоминаю, что все питонисты обмазываются декораторами. Я решил не отставать. Написал декоратор db_aware такой, что
Пусть точка входа в наш граф находится в файлике my_agent/graph.py, его мы подаем на вход lgs. В файлике my_agent/nodes.py находится код всех нод графа. Напоминаю, что ноды - это просто функции. Тогда можно написать новую точку входа только для lgs
Выглядит потно, согласен. Но на самом деле, главное здесь - это подход. Ведь он применим ко всем популярным интерпертируемым языкам программирования: python, php, ruby, js.
Например, в php можно тупо перегрузить stream для чтения файлов, и менять код прямо во время чтения интерпретатором исходников. Именно так работает пакет dg/bypass-finals, позволяющий мокать final классы.
Самое главное, помните, что monkey patch следует использовать только при разработке! В продакшне использовать подобное - это надо быть очень смелым, либо очень тупым. Лучше не надо.
В комментах никто не написал, как бы это делал (эх 😔), поэтому дам ответ сам: monkey patch - это возможность менять код в рантайме.
Как же это выглядит в моем случае. У меня тулза - это вонючий langgraph studio (lgs), и мне надо, чтоб во всем коде, при запуске через lgs было доступно подключение к бд.
Напоминаю, что все питонисты обмазываются декораторами. Я решил не отставать. Написал декоратор db_aware такой, что
@db_aware
async def some_func():
# db стопроц будет тут
db = get_db()
# далее в коде юзаем db в хвост и гриву
Пусть точка входа в наш граф находится в файлике my_agent/graph.py, его мы подаем на вход lgs. В файлике my_agent/nodes.py находится код всех нод графа. Напоминаю, что ноды - это просто функции. Тогда можно написать новую точку входа только для lgs
# Исходный пакет с нодами
NODES_MODULE: Final[str] = "my_agent.nodes"
class DbAwareNodes(ModuleType):
def __init__(self, module: str):
super().__init__(module)
# Сохраняем исходные функции
self._original_nodes = importlib.import_module(NODES_MODULE)
# __getattr__ вызывается когда интерпретатор импортирует имя из модуля
def __getattr__(self, name):
# Находим исходную функцию
node = getattr(self._original_nodes, name)
# Декоратор работает только с корутинами
if iscoroutinefunction(node):
# Декорируем исходную функцию
return db_aware(node)
return node
# Здесь подменяем дефолтный модуль на наш пропатченный
sys.modules[NODES_MODULE] = DbAwareNodes(NODES_MODULE)
# Экспортируем наш граф, будто это точка входа.
from pain_agent.graph import graph
__all__ = ["graph"]
Выглядит потно, согласен. Но на самом деле, главное здесь - это подход. Ведь он применим ко всем популярным интерпертируемым языкам программирования: python, php, ruby, js.
Например, в php можно тупо перегрузить stream для чтения файлов, и менять код прямо во время чтения интерпретатором исходников. Именно так работает пакет dg/bypass-finals, позволяющий мокать final классы.
Самое главное, помните, что monkey patch следует использовать только при разработке! В продакшне использовать подобное - это надо быть очень смелым, либо очень тупым. Лучше не надо.
❤3👍3🙈2
Вышло очередное обновление индекса языков программирование TIOBE. Меня прикалывает, как создатели TIOBE продолжают срать себе в штаны, делая вид, что все в порядке👌
"У нас Ada обогнал PHP и Kotlin, а Visual Basic будет попизже Golang. Perl попал в 10ку, а Ruby, даже в 20ке не видно. Typescript мы поместили на 35е место. Вас что-то смущает?.. Нам поебать!" - так прокомментировал свежие данные рейтинга глава TIOBE Вротстислав Хуепутолов.
Ну а если серьезно, когда видишь в одном рейтинге matlab и php, то сразу же вопрос возникает, а для кого это составляется вообще? в чем польза?
The index can be used to check whether your programming skills are still up to date or to make a strategic decision about what programming language should be adopted when starting to build a new software system.
Я считаю, что индекс можно использовать для проверки того, на сколько челики в TIOBE ебнулись в своих метриках, который нахер никому кроме них самих не нужны. Тупее было бы только составить рейтинг по количеству букв в названии языка. Хотя нет, даже это имело бы больше смысла😡
Единственное, что могло бы оправдать этот рейтинг из жопы, это если бы TIOBE просто бабок занесли. Но мы об этом никогда не узнаем.
"У нас Ada обогнал PHP и Kotlin, а Visual Basic будет попизже Golang. Perl попал в 10ку, а Ruby, даже в 20ке не видно. Typescript мы поместили на 35е место. Вас что-то смущает?.. Нам поебать!" - так прокомментировал свежие данные рейтинга глава TIOBE Вротстислав Хуепутолов.
Ну а если серьезно, когда видишь в одном рейтинге matlab и php, то сразу же вопрос возникает, а для кого это составляется вообще? в чем польза?
The index can be used to check whether your programming skills are still up to date or to make a strategic decision about what programming language should be adopted when starting to build a new software system.
Я считаю, что индекс можно использовать для проверки того, на сколько челики в TIOBE ебнулись в своих метриках, который нахер никому кроме них самих не нужны. Тупее было бы только составить рейтинг по количеству букв в названии языка. Хотя нет, даже это имело бы больше смысла😡
Единственное, что могло бы оправдать этот рейтинг из жопы, это если бы TIOBE просто бабок занесли. Но мы об этом никогда не узнаем.
Че-то в последнее время тяжеловато идет написание постов. Много работы и уходящее лето, когда надо успеть чуток почиллить, - делают свое дело!
Контент план есть, тем много. Темы появляются быстрее, чем успевается о них писать. Но я тот еще писака, поэтому на написание одного поста у меня уходит от 2х часов 😔 Сами понимаете, как с такими таймингами тяжело вписаться в текущую жизнь.
Тем не менее, будем надеяться, что с приходом осени все стабилизируется. На улице будет нечего делать, и придется заниматься эскопизмом в канале 😊
Контент план есть, тем много. Темы появляются быстрее, чем успевается о них писать. Но я тот еще писака, поэтому на написание одного поста у меня уходит от 2х часов 😔 Сами понимаете, как с такими таймингами тяжело вписаться в текущую жизнь.
Тем не менее, будем надеяться, что с приходом осени все стабилизируется. На улице будет нечего делать, и придется заниматься эскопизмом в канале 😊
❤2🤯2
Но чтобы перерывы в постах о программировании не были такими уж длинными, я воспользуюсь читерной рубрикой "подписчики набрасывают на вентилятор".
Мне тут скинули старую, но презабавнейшую статью What is {} + {} in JavaScript?. В статье автор задается вопросом, а что будет при выполнении следующих операций в js
Спойлер:будут приколы.
Для []+{} ответ '[object Object]'. []+[] - это ''. И наконец, два моих "любимых": {} + [] дает 0, а {} + {} вернет NaN.
Для "любимых" объяснение такое, что первый {} js интерпретирует как пустой блок кода 🤡, а дальше уже приводит второй аргумент к числу в соответствии с действием унарного оператора +. Ну не красота ли! Об остальных можно прочесть в статье.
Может показаться, что всем результатам есть логичное объяснение. И в статье это объяснение дается. Но по факту, это просто торчащие уши плохого дизайна js, с которым приходится мириться и по сей день, используя костыли в виде ts. Запоминать такое поведение категорически противопоказанно для сохранения рассудка! 👆
А если на собеседованиях вас спрашивают про подобные особенности, то можете смело проваливать это интервью, потому что тех. лид долбаеб, и делать в такой компании нечего. Ну либо можете зазубрить кучу таких кейсов и задоминировать! Но будьте осторожны, ведь тогда можно самому ебнуться наглухо и стать вонючим душнилой🤓 Смотрите сами короче
Мне тут скинули старую, но презабавнейшую статью What is {} + {} in JavaScript?. В статье автор задается вопросом, а что будет при выполнении следующих операций в js
[]+{}
[]+[]
{}+[]
{}+{}
Спойлер:
Для []+{} ответ '[object Object]'. []+[] - это ''. И наконец, два моих "любимых": {} + [] дает 0, а {} + {} вернет NaN.
Для "любимых" объяснение такое, что первый {} js интерпретирует как пустой блок кода 🤡, а дальше уже приводит второй аргумент к числу в соответствии с действием унарного оператора +. Ну не красота ли! Об остальных можно прочесть в статье.
Может показаться, что всем результатам есть логичное объяснение. И в статье это объяснение дается. Но по факту, это просто торчащие уши плохого дизайна js, с которым приходится мириться и по сей день, используя костыли в виде ts. Запоминать такое поведение категорически противопоказанно для сохранения рассудка! 👆
А если на собеседованиях вас спрашивают про подобные особенности, то можете смело проваливать это интервью, потому что тех. лид долбаеб, и делать в такой компании нечего. Ну либо можете зазубрить кучу таких кейсов и задоминировать! Но будьте осторожны, ведь тогда можно самому ебнуться наглухо и стать вонючим душнилой🤓 Смотрите сами короче
2Ality
What is {} + {} in JavaScript?
Recently, the lightning talk “Wat” by Gary Bernhardt pointed out an interesting JavaScript quirk: You get unexpected results when you add objects and/or arrays. This post explains those results.
😁5💯2❤1
Прикол. У меня прям сейчас таск по обновлению пакетов. Обновляю-обновляю, и вдруг перестает все собираться. И ошибка такая интересная
Захожу на гитхаб, а тут issue час назад была создана Version 4.4.2 published to npm is compromised.
С одной стороны, как бы круто что в npm так быстро сработали. С другой стороны, че то я себя не очень безопасно щас почувствовал, даже несмотря на то, что этой версии уже нет в npm. Какое-то время эта херабора запускалась у меня локально, пусть и в контейнере.
Вообщем в мире js все как всегда 😔
npm error 404 Not Found - GET https://registry.npmjs.org/debug/-/debug-4.4.2.tgz - Not found
Захожу на гитхаб, а тут issue час назад была создана Version 4.4.2 published to npm is compromised.
С одной стороны, как бы круто что в npm так быстро сработали. С другой стороны, че то я себя не очень безопасно щас почувствовал, даже несмотря на то, что этой версии уже нет в npm. Какое-то время эта херабора запускалась у меня локально, пусть и в контейнере.
Вообщем в мире js все как всегда 😔
GitHub
(RESOLVED) Version 4.4.2 published to npm is compromised · Issue #1005 · debug-js/debug
MESSAGE FROM @Qix- : PLEASE SEE #1005 (comment) FOR LATEST UPDATES. Version not present in this repo has been pushed out to npm. https://www.npmjs.com/package/debug/v/4.4.2?activeTab=code src/index...
👍1😱1
А я отвечу постом на комментарий выше про то, что это касается не только js.
Да, безусловно, такое может произойти в любой экосистеме, не только в js. Везде есть уязвимости!
Но js отличает то, что здесь какое-то неадекватное количество peer dependencies. Авторы пакетов на каждый чих используют другой сторонний пакет. Мемный пакет is-odd все еще с нами, и у него ебейшее количество скачиваний в неделю. А истории про то, что папка node_modules занимает гигабайты - это вообще-то норма, а не исключение.
Именно потому что в папке node_modules лежат миллиарды пакетов, вероятность получить уязвимость кратно возрастает!
У меня 3 экосистемы на поддержке: js, php и python. И раз в полгода мне надо обновлять пакеты для аудита. И я хочу сказать, что если у вас более менее серьезный проект, то довести количество уязвимостей до 0 в js нереально. Мне ни разу не удавалось это даже для внутренних простеньких проектов. В то же время для php и python отсутствие уязвимостей - это скорее норма.
Конкретно в случае с пакетом debug это зависимость express
А самое смешное то, что я вот откатил этот злоебучий пакет до предыдущей версии, а в нем 7 критических уязвимостей 🤡
Поэтому нет, я не соглашусь, что оно везде все так. В js количество уже перетекло в качество. Точнее в его отсутствие.
Да, безусловно, такое может произойти в любой экосистеме, не только в js. Везде есть уязвимости!
Но js отличает то, что здесь какое-то неадекватное количество peer dependencies. Авторы пакетов на каждый чих используют другой сторонний пакет. Мемный пакет is-odd все еще с нами, и у него ебейшее количество скачиваний в неделю. А истории про то, что папка node_modules занимает гигабайты - это вообще-то норма, а не исключение.
Именно потому что в папке node_modules лежат миллиарды пакетов, вероятность получить уязвимость кратно возрастает!
У меня 3 экосистемы на поддержке: js, php и python. И раз в полгода мне надо обновлять пакеты для аудита. И я хочу сказать, что если у вас более менее серьезный проект, то довести количество уязвимостей до 0 в js нереально. Мне ни разу не удавалось это даже для внутренних простеньких проектов. В то же время для php и python отсутствие уязвимостей - это скорее норма.
Конкретно в случае с пакетом debug это зависимость express
+-- debug@4.4.1
`-- express@5.1.0
+-- body-parser@2.2.0
| `-- debug@4.4.1 deduped
+-- debug@4.4.1 deduped
+-- finalhandler@2.1.0
| `-- debug@4.4.1 deduped
+-- router@2.2.0
| `-- debug@4.4.1 deduped
`-- send@1.2.0
`-- debug@4.4.1 deduped
А самое смешное то, что я вот откатил этот злоебучий пакет до предыдущей версии, а в нем 7 критических уязвимостей 🤡
Поэтому нет, я не соглашусь, что оно везде все так. В js количество уже перетекло в качество. Точнее в его отсутствие.
👍2☃1
Я уже 5 лет плотничком работаю с Doctrine ORM. Работа у меня разнообразная. Пишем мы и новый код, с новыми таблицами в бд. Но также имеется большая легаси база говна данных, на которую мы старательно натягиваем Doctrine. Короче, всякое повидал за эти годы, в том числе даже поконтрибьютил в саму Doctrine.
Несмотря на то, что в целом впечатления от Doctrine благостное (по сравнению с тем же Eloquent хех), эта ORM может вставить палки в колеса. Как и любой инструмент. Об этом я написал свой очередной лонгрид Как Doctrine ORM ломает вашу архитектуру.
Я постарался рассказать об основных принципах работы этой ORM так, чтоб было понятно даже тем, кто никогда не работал с Doctrine. А по скольку Doctrine - это классический пример Data Mapper, все эти принципы могут быть применены к другим Data Mapper ORM, например Hibernate и SQLAlchemy.
А от тех, кто тоже успел поработать с Doctrine, жду накидывания на меня какашек о том, что я просто все неправильно понял 😘
Несмотря на то, что в целом впечатления от Doctrine благостное (по сравнению с тем же Eloquent хех), эта ORM может вставить палки в колеса. Как и любой инструмент. Об этом я написал свой очередной лонгрид Как Doctrine ORM ломает вашу архитектуру.
Я постарался рассказать об основных принципах работы этой ORM так, чтоб было понятно даже тем, кто никогда не работал с Doctrine. А по скольку Doctrine - это классический пример Data Mapper, все эти принципы могут быть применены к другим Data Mapper ORM, например Hibernate и SQLAlchemy.
А от тех, кто тоже успел поработать с Doctrine, жду накидывания на меня какашек о том, что я просто все неправильно понял 😘
👍7
Все еще работаем над llm-based FastAPI сервисом. Создал сам себе issue: нужна возможность периодически выполнять какие-то задачи, в народе именуемых cronjobами. Поскольку fastapi - это современный веб фреймворк тупо роутер запросов, такой функционал нам не завезли из коробки. Но задача довольно классическая, проблем быть не должно.
Кроме того,бох девопс дал нам кубернетис с его встроенными CronJobs. Поэтому изечно можем раз в минуту дергать какой-то сервис по ендпоинту /run-cron. Нам лишь нужно
* хранить и отслеживать статус джоб
* парсить cronexpr и решать, какие джобы щас запустить
* определять, если джоба зависла и сбрасывать статус
Это такой bare minimum, который бы меня устроил.
Гугл и ллмки выдали мне решение: билиотека apscheduler. Куча звезд на гитхабе, делает все то, что описано выше и даже больше. Короче, царский подгодон.
Начал интегрироваться и вместо cronjobов сделал blowjobы. Потому что этот apscheduler сам себе экзекутор задач. Он ни в какую не хотел привязываться к внешнему тригеру, потому что он сам знает, когда ему запускать задачи. А мне зачем экзекутор джобов в каждом поде приложения??
Потратив целый день на попытки скрестить жопу сужом питоном, я понял, что за этот день я бы уже написал свое решение. Единственное, что мне нужно, это либа для парсинга cronexpr. Ну уж с этим то проблем быть не должно? Не должно ведь, python?
Самая популярная либа для парсинга cron экспрешнов называется croniter. И она официально не поддерживается с конца 2024 года 🤡 На стэковерфлоу в связи с этим советуют воспользоваться новой либой cron-converter, у которой невероятные 46 звезд на гитхабе (кстати, поставил 47ю) 🤩 Ну тут особо выбора нет, ибо писать парсер с нуля - это задача для пет проектов.
И вот получается, что в 2к25 я все еще занимаюсь тем, что было сделано во многих фреймворках и цмсках в нулевые. Странно это как-то... Может я неправильно это готовлю.
Кто-то может подумать, что я тут опять накидываю на питон. На самом деле уже 4 года в проде на Symfony также крутится собственное решение с кронджобами, которое делает все тоже самое. Ибо Scheduler компонент завезли только в версии 6.3. И я его даже не пробовал 😔 Но хотя бы в пхп у либы dragonmantank/cron-expression, которая парсит cron expression, 4.7к звезд, а у питоновсокого croniter 485 🤷 вообще нет уверенности, что кому-то это надо.
Поделитесь, как сами решаете проблему с кроном? сразу ставите celery? запускаете отдельный сервис с тем же кодом, но чисто повыполнять таски? или целиком на кубовых джобах живете?
Кроме того,
* хранить и отслеживать статус джоб
* парсить cronexpr и решать, какие джобы щас запустить
* определять, если джоба зависла и сбрасывать статус
Это такой bare minimum, который бы меня устроил.
Гугл и ллмки выдали мне решение: билиотека apscheduler. Куча звезд на гитхабе, делает все то, что описано выше и даже больше. Короче, царский подгодон.
Начал интегрироваться и вместо cronjobов сделал blowjobы. Потому что этот apscheduler сам себе экзекутор задач. Он ни в какую не хотел привязываться к внешнему тригеру, потому что он сам знает, когда ему запускать задачи. А мне зачем экзекутор джобов в каждом поде приложения??
Потратив целый день на попытки скрестить жопу с
Самая популярная либа для парсинга cron экспрешнов называется croniter. И она официально не поддерживается с конца 2024 года 🤡 На стэковерфлоу в связи с этим советуют воспользоваться новой либой cron-converter, у которой невероятные 46 звезд на гитхабе (кстати, поставил 47ю) 🤩 Ну тут особо выбора нет, ибо писать парсер с нуля - это задача для пет проектов.
И вот получается, что в 2к25 я все еще занимаюсь тем, что было сделано во многих фреймворках и цмсках в нулевые. Странно это как-то... Может я неправильно это готовлю.
Кто-то может подумать, что я тут опять накидываю на питон. На самом деле уже 4 года в проде на Symfony также крутится собственное решение с кронджобами, которое делает все тоже самое. Ибо Scheduler компонент завезли только в версии 6.3. И я его даже не пробовал 😔 Но хотя бы в пхп у либы dragonmantank/cron-expression, которая парсит cron expression, 4.7к звезд, а у питоновсокого croniter 485 🤷 вообще нет уверенности, что кому-то это надо.
Поделитесь, как сами решаете проблему с кроном? сразу ставите celery? запускаете отдельный сервис с тем же кодом, но чисто повыполнять таски? или целиком на кубовых джобах живете?
🔥1
Итак, настал момент истины. На сколько же php быстрее golang?
И нет, я не ошибся. Дмитрий Кириллов в своем шикарном докладе показал, что php с jit может быть быстрее Си (базового). Это на столько меня вдохновило, что я решил поиграться с этим сам. Пришлось даже виртуалочку для этого арендовать.
Я использовал ту же самую задачу о рюкзаке из доклада. Вот код на golang.
Код на пхп взял прям отсюда.
Итак, вот, что нам выдал perf для 10 запусков golang(1.25.2)
А вот для php(8.4.13)
Таким образом, мы видим, что php реально очень быстр, когда дело касается CPU-bound задач. Ну и конечно, когда вы поприседали с ним, чтоб убрать все ненужные опкоды. Мы получили, что пхп быстрее почти на 20%.
Изначально я тестировал этот код на версии php 8.3. И там результат был таков
Что конечно все еще быстрее голэнг, но не так впечатляюще. То есть разрабы php действительно хорошо поработали над jit в 8.4!👍
А еще я поставил nodejs и python, раз уж пошла такая пляска. И я вынужден признать, что ребята, которые пилят V8, рил настоящие гении. Для ноды результат получился
Что медленее php8.4, но быстрее и 8.3 и golang. Но при этом, в отличии от php, мне не нужно было делать ничего специального. Я просто написал
и оно уже быстрее голэнг!
Что касается питона (3.12), то тут все выглядит как-то так 😂
Лан, нет смысла сравнивать язык с jit и без jit. Понятно, что это будет избиение младенца.
Поэтому я решил отключить jit в php. Более того, я решил использовать версию кода на пхп без всяких извращений с проверками на out of bound conditions. Таким образом, код стал выглядеть, как обычный код на пыхе. Итого имеем
То есть питон более, чем в 5 раз медленее пхп.
А что в итоге? Понятно, что это все синтетика. Понятно, что, когда мы начнем писать бизнес логику, начнем вызывать методы у объектов, начнем массивами всячески оперировать, то картина будет немного другой. Конечно статически типизированный и компилируемый голэнг все таки в другой лиге играет. Особенно в плане потребления памяти.
Но если вдруг перед вами стоит задача, где надо тупо дробить числа, а у вас пхп - не бегите переписывать этот кусок на голэнг, шоб было побыстрее! Лучше вместо создания нового микросервиса посмотрите доклад Дмитрия, охуейте, а затем примените новые знания на практике 👆
P.S. Мечтаю стать Дмитрием, когда вырасту
И нет, я не ошибся. Дмитрий Кириллов в своем шикарном докладе показал, что php с jit может быть быстрее Си (базового). Это на столько меня вдохновило, что я решил поиграться с этим сам. Пришлось даже виртуалочку для этого арендовать.
Я использовал ту же самую задачу о рюкзаке из доклада. Вот код на golang.
package main
import "fmt"
const w = 700
const h = 700
const l = 700
const target = 1500
func main() {
ans := 0
for i := 0; i < w; i++ {
for j := 0; j < h; j++ {
for k := 0; k < l; k++ {
vol := (i + 3) * (j + 4) * (k + 5)
if vol == target {
ans += 2
}
}
}
}
fmt.Println(ans)
}
Код на пхп взял прям отсюда.
Итак, вот, что нам выдал perf для 10 запусков golang(1.25.2)
0.353181 +- 0.000158 seconds
А вот для php(8.4.13)
0.2895 +- 0.0119 seconds
Таким образом, мы видим, что php реально очень быстр, когда дело касается CPU-bound задач. Ну и конечно, когда вы поприседали с ним, чтоб убрать все ненужные опкоды. Мы получили, что пхп быстрее почти на 20%.
Изначально я тестировал этот код на версии php 8.3. И там результат был таков
0.33962 +- 0.00224
Что конечно все еще быстрее голэнг, но не так впечатляюще. То есть разрабы php действительно хорошо поработали над jit в 8.4!👍
А еще я поставил nodejs и python, раз уж пошла такая пляска. И я вынужден признать, что ребята, которые пилят V8, рил настоящие гении. Для ноды результат получился
0.32645 +- 0.00288
Что медленее php8.4, но быстрее и 8.3 и golang. Но при этом, в отличии от php, мне не нужно было делать ничего специального. Я просто написал
const calc = (w, h, l, target) => {
let ans = 0;
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
for (let k = 0; k < l; k++) {
const vol = (i + 3) * (j + 4) * (k + 5);
if (vol === target) {
ans += 2;
}
}
}
}
return ans;
};
console.log(calc(700, 700, 700, 1500));и оно уже быстрее голэнг!
Что касается питона (3.12), то тут все выглядит как-то так 😂
25.958 +- 0.235 seconds
Лан, нет смысла сравнивать язык с jit и без jit. Понятно, что это будет избиение младенца.
Поэтому я решил отключить jit в php. Более того, я решил использовать версию кода на пхп без всяких извращений с проверками на out of bound conditions. Таким образом, код стал выглядеть, как обычный код на пыхе. Итого имеем
4.9320 +- 0.0439 seconds
То есть питон более, чем в 5 раз медленее пхп.
А что в итоге? Понятно, что это все синтетика. Понятно, что, когда мы начнем писать бизнес логику, начнем вызывать методы у объектов, начнем массивами всячески оперировать, то картина будет немного другой. Конечно статически типизированный и компилируемый голэнг все таки в другой лиге играет. Особенно в плане потребления памяти.
Но если вдруг перед вами стоит задача, где надо тупо дробить числа, а у вас пхп - не бегите переписывать этот кусок на голэнг, шоб было побыстрее! Лучше вместо создания нового микросервиса посмотрите доклад Дмитрия, охуейте, а затем примените новые знания на практике 👆
P.S. Мечтаю стать Дмитрием, когда вырасту
👏12👍5🔥3