Для тех, кто хостит пет-проекты не в кубере, а просто в условном docker (как я например), но хочет настроить CI/CD с помощью gitlab - максимально простой мануал как это сделать: билд на gitlab-runner (который тоже можно поднять на своём же сервере, чтобы не использовать часы runner'а gitlab), docker-compose файл из шаблона и
Не забудьте выключить гитлабовские runner'ы в CI/CD Settings (и оставить только свой), а также добавлять тег вашего runner в .gitlab-ci.yml (да, я часто забываю).
#gitlab #deploy
docker compose up
по SSH для этого образа со стадии билда.Не забудьте выключить гитлабовские runner'ы в CI/CD Settings (и оставить только свой), а также добавлять тег вашего runner в .gitlab-ci.yml (да, я часто забываю).
#gitlab #deploy
👍8
Интернеты принесли забавную штуку bolt.new, которая по текстовому описанию генерит проект. Год назад я записывался в wait list одного проекта, который планировал что-то подобное но он явно не взлетел, потому что с тех пор не было никаких новостей. А этот видимо взлетел (ну или делает вид что так). На простеньких конструкциях как на скриншоте - работает норм.
Пока неясно насколько большой проект оно сможет держать в контексте выполнения и рефакторить по новым условиям. #ai
Пока неясно насколько большой проект оно сможет держать в контексте выполнения и рефакторить по новым условиям. #ai
👍4
Очень простой и строготипизированный PredicateBuilder - когда надо собрать выражение в EF вида
(или других условий) и вот этих условий в OR неизвестное (динамическое) количество, зависящее от внешних условий.
С традиционным AND обычно никаких проблем:
А вот с OR такого не прокатит, так что PredicateBuilder спасает в этом случае. #dotnet
select ...
from table1
where (x=1 and y=2) or (x=3 and y=5) or (x=3 and y=5 and coef>1)
(или других условий) и вот этих условий в OR неизвестное (динамическое) количество, зависящее от внешних условий.
С традиционным AND обычно никаких проблем:
var q = db.Items.AsQueryable();
q = q.Where(...);
q = q.Where(...);
...
var items = await q.ToArrayAsync();
А вот с OR такого не прокатит, так что PredicateBuilder спасает в этом случае. #dotnet
👍5🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
github profile генератор, который генерит markdown страничку для профиля. Не знаю зачем, но выглядит симпатишно :))
🔥4
Несколько полезных запросов для Clickhouse на gist.github.com
(в продолжение поста по Postgres) #clickhouse
(в продолжение поста по Postgres) #clickhouse
👍1
Как использовать Result<T> и немного LINQ для railway oriented programming или "у вас result'янка". С одной стороны выглядит красиво и реализует short-circuit, когда фейл одного из степов сразу возвращает Result.Error и всё прекращается. Но под капотом некоторое количество не оч кросивого кода. Наверное имеет смысл для ознакомления, но использовать я такое не буду. #dotnet
👍3❤1
инструмент для мониторинга исходящих http запросов
А также 9 интересных статей на тему внутренних штук дотнета (для собирания метрик в т.ч.) с примерами кода #dotnet
dotnet tool install -g dotnet-http
А также 9 интересных статей на тему внутренних штук дотнета (для собирания метрик в т.ч.) с примерами кода #dotnet
🔥7👀1
Коротенькая статья по хранению векторов для #LLM (в статье для Ollama)
🔥2
Я тут ковырял MSSQL в одном проекте, а там использовалось page data compression для разного второстепенного барахла, что здорово сжимало данные и уменьшало IO. И надо сказать page data compression отлично подходит если данные меняются редко, а жмутся хорошо. И вспомнил, что в Postgres есть аналог, ну как аналог... штука, которую тоже можно использовать для сжатия данных - TOAST. И нашёл статью, где неплохо описывается в т.ч. структура (как оно лежит внутри) - и да, это полезно для понимания процессов и применения - где/когда можно, а где не стоит. #postgres
👍6🔥1
В .net 9 завезли поддержку OAuth 2.0 Pushed Authorization Requests и вот статья с примерами реализации (да, на примере Duende IdentityServer) #dotnet
🔥6🤯1
Чятики принесли интересную штуку - какой-то новый профайлер для дотнета. Опенсурс, но по фичам надо сравнивать с dotProfiler и dotMemory конечно. #dotnet
👍2
Ещё один закат солнца вручную - message queue поверх Postgres - pgmq.
Зачем? Не знаю.
Почему? Потому что могут!
Пытаюсь придумать кейс для использования, но что-то пока не выходит. Вроде и версия 1.45, хоть щас в прод! :))) #postgres
Зачем? Не знаю.
Почему? Потому что могут!
Пытаюсь придумать кейс для использования, но что-то пока не выходит. Вроде и версия 1.45, хоть щас в прод! :))) #postgres
🤔3🔥1
Интересная книга "The Internals of PostgreSQL" с картинками! По краткому прочтению - must have для разработчиков. #postgres
👍7
Тут на соседнем канале зашла речь про ускорение некоторых алгоритмов с помощью SIMD и я побыстрому накидал реализацию двух - косинусное сходство и корреляцию Пирсона (на скриншоте бенчи для него, для косинусного сходства - в камментах в gist). Алгоритмы как будто прямо таки созданы для Single Instruction/Multiple Data :)
Первый блок на скриншоте - просто мап на Vector<double> и дальнейшие операции, ничо сложного, но даже это даёт 6-кратный буст. Второй блок с float, тут ещё побыстрее, просто потому что элемент в 2 раза тоньше и за один чпок забирается в два раза больше элементов по сравнению с double.
Но вот дальше там был ещё один кейс, когда входные данные короче И double И float - например short. И вот тут становица всё ещё интереснее: отмапленый в Vector256<short> забирает сразу 16 элементов входного массива. Напрямую в Vector256<float> такое не смапиш конечно, поэтому операция двухэтапная - сначала GetLower/GetUpper по 8 элементов экспандяца до int (32 бита = 256 бит), а потом кастяца до float (тоже 256 бит).
Вроде выглядит некоторыми костылями, но это даёт 14-кратный буст даже на длинных массивах, которые гарантированно не влезают в L2 кэш. Если кастить в 32-битный float конечно, с double ситуация пожиже - там буст ровно в два раза хуже (~x7), что вполне логичо :))
Судя по всему выполнение SIMD инструкций тут отлично сочетается с асинхронностью L1/L2-кэша - пока локальные данные кастяца, множаца и складываюца - в кэш подтягиваются следующие порции данных и к моменту следующей итерации они уже там. #simd
Первый блок на скриншоте - просто мап на Vector<double> и дальнейшие операции, ничо сложного, но даже это даёт 6-кратный буст. Второй блок с float, тут ещё побыстрее, просто потому что элемент в 2 раза тоньше и за один чпок забирается в два раза больше элементов по сравнению с double.
Но вот дальше там был ещё один кейс, когда входные данные короче И double И float - например short. И вот тут становица всё ещё интереснее: отмапленый в Vector256<short> забирает сразу 16 элементов входного массива. Напрямую в Vector256<float> такое не смапиш конечно, поэтому операция двухэтапная - сначала GetLower/GetUpper по 8 элементов экспандяца до int (32 бита = 256 бит), а потом кастяца до float (тоже 256 бит).
Вроде выглядит некоторыми костылями, но это даёт 14-кратный буст даже на длинных массивах, которые гарантированно не влезают в L2 кэш. Если кастить в 32-битный float конечно, с double ситуация пожиже - там буст ровно в два раза хуже (~x7), что вполне логичо :))
Судя по всему выполнение SIMD инструкций тут отлично сочетается с асинхронностью L1/L2-кэша - пока локальные данные кастяца, множаца и складываюца - в кэш подтягиваются следующие порции данных и к моменту следующей итерации они уже там. #simd
👍11🤯5🔥4
В продолжение поста, теперь на столе коэффициент детерминации R² (gist). Тут что-то пошло не совсем так: если использовать прямой подход с мапом в Vector256<T> - то буст всего х4 на double и x6 на float (причем повторяемость практически не зависит от размера массива, а значит дело не в кэше который всё успевает и никак не влияет на перф, а в вычислениях).
Однако, если сделать финт ушами (второй скриншот) - и смапить в Vector512<T> - то всё становица чуточку лучше. И тут неважно, что процессор не умеет нативно AVX512, Vector512<T> здесь просто как контейнер для двух Vector256<T>. Здесь получается.... классический loop unrolling, когда за одну итерацию забирается два Vector256<T> (lower/upper) и дальше они ровно также как в ручном loop unrolling складываюца/умножаются в цикле в по прежнему в Vector256<T>.
Это помогает больше чем в 1.5 раза к обычному способу с Vector256 - буст с х4 до ~х5.5 (на double) и с х7.6 до ~x12.5 (на float). Причем на массивах больших, которые не помещаются в L1 кэш - разрыв в перфе больше. Подозреваю, что по причине как в предыдущем посте. #simd
Однако, если сделать финт ушами (второй скриншот) - и смапить в Vector512<T> - то всё становица чуточку лучше. И тут неважно, что процессор не умеет нативно AVX512, Vector512<T> здесь просто как контейнер для двух Vector256<T>. Здесь получается.... классический loop unrolling, когда за одну итерацию забирается два Vector256<T> (lower/upper) и дальше они ровно также как в ручном loop unrolling складываюца/умножаются в цикле в по прежнему в Vector256<T>.
Это помогает больше чем в 1.5 раза к обычному способу с Vector256 - буст с х4 до ~х5.5 (на double) и с х7.6 до ~x12.5 (на float). Причем на массивах больших, которые не помещаются в L1 кэш - разрыв в перфе больше. Подозреваю, что по причине как в предыдущем посте. #simd
🔥3👍1