Golang Дайджест
8.15K subscribers
37 photos
1 file
185 links
Самое интересное из мира Go: новости, статьи, проекты, сервисы, изменения в языке и др.

Посты публикуются не часто - только самое важное, с чем я лично ознакомился.

Поэтому можно не мьютить канал =)

Обратная связь: @justskiv
Download Telegram
🛠 AI агент в 400 строк кода на Go

https://ampcode.com/how-to-build-an-agent

Оличная статья от Thorsten Ball про создание собственного ИИ агента. Особая прелесть в том, что автор объясняет всё настолько просто и доступно, что осилить её можно буквально за полчаса, получив полностью рабочего агента (с перспективами для развития, конечно).
В общем, всё в лучших традициях его замечательных книг Interpreter In Go и Compiler In Go, но в формате короткой статьи.

Это очень полезное упражнение для понимания того, как агенты устроены внутри. Да и в целом, это очень весело, вдохновляет на собственные эксперименты.

Очень рекомендую, я уже написал по ней своего, и даже немного прокачал, просто веселья ради. Мне очень понравилось

Конечно, замену полноценному агенту вы таким образом не получите, впереди ещё много работы. Но главное, что отправная точка уже есть.

————

И вдогонку ещё одна статья на ту же тему от нашего соотечественника на Хабре

#ai_agent #diy #llm
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥394👍2
Полноценное RAG-приложение на Go — безумие?

https://habr.com/ru/articles/930090/

Хорошая статья от начинающего разработчика, который решил пойти против течения и построить RAG-систему на Go, вместо привычного Python.
Спойлер: вышло интересно, хоть и с нюансами.

Получилась довольно нетривиальная система:

- 5 микросервисов с разделением ответственности
- Kafka в роли брокера сообщений
- Ollama для локального inference на собственной GPU
- gRPC-стриминг + SSE для передачи токенов в реальном времени (без вебсокетов)

👴 Учитываем, что это пет-проект, и архитектура немного перегружена ради учебных целей.

Узкие места и проблемы:
Главный bottleneck оказался в Ollama — весь трафик генерации и эмбеддингов упирается в неё, локальная GPU тянет всего один запрос за раз.

Мои мысли по оптимизации:

- Для продакшена точно нужен vLLM кластер или платные API (OpenAI/Anthropic)
- Kafka здесь оверкилл — NATS или Redis Streams справятся не хуже и проще в деплое
- Можно добавить кеширование эмбеддингов и результатов поиска
- Рассмотреть pgvector вместо отдельного векторного хранилища

В целом, статья полезная, и выбор Go вместо Python для RAG выглядит вполне логично — действительно, RAG это по большей части инфраструктура, а не ML-магия.

Особенно ценно, что автор честно описывает проблемы и не идеализирует решение.

#article #rag #llm
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3919🤔3
Forwarded from Go Update
🔀 Динамический GOMAXPROCS 🔀

До релиза Go 1.25 осталось около недели, а значит, самое время восполнить пробелы и написать всё то, о чем я (по-хорошему) должен был рассказать в течение последнего полугодия разработки новой версии языка. Начнем с небольшого, но значимого изменения: динамического GOMAXPROCS.

Для тех, кто не в курсе: Go позволяет определить число горутин, которые могут одновременно выполняться в пределах рантайма. Ключевое слово — одновременно. Это значит, что горутин у вас может быть сколько угодно, но выполняться из них (лопатить код, а не находится в ожидании сети, файлов или ответа из сишной либы), в момент времени, будет только число, указанное в GOMAXPROCS. По-хорошему, это число обычно равно числу физических ядер на вашем CPU. Но в серверных окружениях начинаются тонкости, главная из которых, cgroups, является столпом для Docker и K8S.

Смысл вот в чем: в контейнеризированном мире на приложение может быть выделено даже не ядро, а фракция или квота, при этом значения сии могут быть динамическими и изменяться в процессе работы кластера. Процесс может ошибочно исходить из того, что у него есть 64 ядра всего блейда (и как следствие — возможность 64-х активных потоков), но по факту доступных именно нашему процессу ядер намного меньше. И это не вдаваясь в подробности таких вещей, как "привязка к ядрам CPU конкретного процесса" которые актуальны в NUMA окружениях.

До версии Go 1.25 эту проблему частично решала библиотека automaxprocs от Uber, которая выставляла значения наиболее приближенные к ожидаемым оркестратором. Но делала она это только один раз и только на старте. Кроме того, много людей банально не знали об этой тонкости работы рантайма Go и, как следствие, неправильно использовали доступные ресурсы CPU.

Начиная с версии Go 1.25, GOMAXPROCS будет не только выставляться автоматически, но и периодически обновляться в течение жизни приложения, в зависимости от того, как меняется внешнее окружение.

На изменение GOMAXPROCS будут влиять в совокупности три вещи:

• Изменение числа логических ядер на машине.
• Изменение привязки приложения к ядрам CPU.
• И, специально для Linux, средний лимит пропускной способности, основанный на квотах CPU cgroup.

Стоит заметить, что это изменение, при всех его очевидных плюсах, имеет один, но явный неочевидный минус — если вы шардировали кеши по числу GOMAXPROCS то вас ожидают очень неприятные паники или скачки нагрузки. Поэтому, если-же вас по какой-то причине не устраивает новое поведение, то у вас есть целых три варианта:

• Вы можете не выставлять в go.mod версию go 1.25.x — обновление придёт к вам только когда вы захотите перейти на поведение языка версии 1.25.
• Вы можете самостоятельно выставить GOMAXPROCS с помощью переменных окружения или с помощью функции GOMAXPROCS. В таком случае автообновление будет выключено, и рантайм доверится вашему суждению.
• Также можно оставить прошлое поведение с помощью GODEBUG переменных containermaxprocs=0 и updatemaxprocs=0.

P.S. Для полноценного мониторинга Go теперь держит в памяти дескриптор доступа к файлам cgroups на время жизни всего процесса.
🔥296👍4
Forwarded from Go Update
🏎️ Об оптимизациях в Go 1.25 🏎️

В новом релизе, как и всегда, к нам приедут новые оптимизации для компилятора. Две из них меня заинтересовали больше всего:

• Цепочка из четырёх 1, 2, 3, 4 PR, суть которых можно описать с помощью одного примера:


var x []int

for i := 0; i < 4; i++ {
x = append(x, i)
}


Если в Go 1.24 и ранее такой код приводил к аллокации в хипе, то начиная с Go 1.25 — нет. А всё просто: make и append теперь, в большинстве случаев, не аллоцируют память в хип до 32 байтов включительно. Вместо этого они используют память на стеке и лишь при превышении объёма начинают идти в хип. Такая вот консервативная оптимизация для слайсов всех типов.

Нулевые значения и "константные" переменные больше не аллоцируют память в хипе при присвоении значения интерфейсу. Продемонстрировать проще всего вот так:


type doubleInt struct{ value1, value2 int }

localVariable := doubleInt{value1: 3, value2: 2}
globalAny = any(localVariable)

localVariable2 := doubleInt{}
globalAny2 = any(localVariable2)


Если ранее подобный код приводил к аллокации, то теперь компилятор достаточно умён, чтобы на этапе компиляции выделить специальное read-only место в памяти и использовать именно его во время исполнения. Особенно приятно, что reflect.Value.IsZero теперь использует сравнение по указателю для нулевых значений структур и массивов, что существенно удешевляет проверку.
👍3816🔥9
Forwarded from Go Update
🎉 Вышел Go 1.25! 🎉

Пока я не успел статью про новый сборщик мусора написать, поэтому быстро пробегусь по основным нововведениям которых не касался в прошлых записях.

♻️ Бинарей в комплекте теперь меньше. Разработчики компилятора активно использовать команду go tool у себя внутри, что убирает необходимость поставлять заготовки в комплекте. Но как минимум go build и go test бинари все еще на месте.

— Новая директива ignore в go.mod. Подробное описание тут. Если в вкратце: для этого вы раньше использовали каталог testdata и каталоги которые начинаются с точки.

— Когда go команда обновляет go 1.xx.y директиву в go.mod она больше не добавляет toolchain директиву.

go vet теперь ругается на неправильное использование sync.WaitGroup.Add и fmt.Sprintf("%s:%d", host, port) ибо есть net.JoinHostPort.

🍵 Новый экспериментальный сборщик мусора. О нем статья будет позже.

🔀️️️️️️ Новый тип runtime/trace.FlightRecorder позволяет записывать только значимые события, а не всё подряд для tracing’га (под капотом используется циклический буфер, который помнит N последних секунд).

🛠 Компилятор теперь генерирует дебаг-инфу в формате DWARF5. Практический итог: бинари едят меньше места и быстрее комбинируются.

🏎️️️️️️ Новый экспериментальный пакет encoding/json/v2. По хорошему про него тоже надо писать отдельную статью, но если в кратце — он намного быстрее того что было внутри encoding/json. А другая хорошая новость заключается в том, что если вы включили GOEXPERIMENT=jsonv2 то больше ничего менять не надо, так как encoding/json сам подключит новую внутряку.

— Тип os.Root приобрел несколько новых методов.

🏎️️️️️️ Функция reflect.TypeAssert позволяет приводить типы из reflect.Value в конкретный тип, минуя потенциально аллоцирующий вызов reflect.Value.Interface.

— Директива GODEBUG=checkfinalizers=1 позволяет понять, как дела в вашей очереди cleanup’ов и finalizer’ов во время каждого GC.

SetDefaultGOMAXPROCS позволяет сбросить настройки GOMAXPROCS если вдруг переменная прилетела через Env или через прошлый вызов GOMAXPROCS.

— Новый метод sync.WaitGroup.Go - больше нет необходимости тащить errgroup если вам не нужен был возврат ошибок и отмена контекста.

🔥testing.T/B/F теперь имеют метод Output() io.Writer который позволяет правильно редиректить вывод внутри вызова теста.

Читать про релиз вот тут.
1🔥44👍2210🤯3
Ещё одна статья про Swiss Tables в Go

https://habr.com/ru/companies/oleg-bunin/articles/934906/

Если вам было мало статей на эту тему, то держите ещё один неплохой подробный разбор:

Попробуем найти ответы на вопросы о том, почему мапы изменились, что лежит в основе новой реализации и как к ней пришли.


#article #swiss_map
👍135🔥3
Как мы обслуживаем 5 млрд карточек в сутки с задержкой меньше 1 мс

https://habr.com/ru/articles/942274/

Классическая история, ребята столкнулись с проблемой выросшего стартапа — PHP-монолит с миллионами товаров начал задыхаться под нагрузкой. Решили вынести самые нагруженные части в отдельные сервисы. Один из них — сервис карточек товаров с жесткими требованиями: 99% ответов за 30 мс, 300к RPS в пике. О нём и пойдёт речь.

Что сделали:

— Двухуровневая архитектура с горячим и холодным хранилищами

— Горячий кеш в памяти с алгоритмом вытеснения 2Q (а не LRU/LFU): защита от sequential scan.

— Сегментирование для многопоточности: разбили кеш по типам моделей данных

— Инвалидация через Redis Streams: декораторы на репозиториях отправляют события об изменениях

— Прогрев после деплоя: собирают статистику популярных товаров и греют только их (старт занимает несколько минут)

Результат: медиана 348 микросекунд при 5 млрд запросов в сутки. Для одной карточки нужно 35 обращений к кешу и данные из 130 сущностей.

————

В подобных статьях меня всегда радует, когда автор честно пишет про проблемы и костыли (неконсистентность между слоями, проблема прогрева).

Немного смущает выбор 2Q "по непонятным причинам" — это же архитектурное решение, а не цвет кнопки 🦄

В целом — must read для тех, кто интересуется высоконагруженными системами.

#article #highload #cache
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥30👍135
Как я пытался засунуть gRPC в браузер — часть первая

https://habr.com/ru/articles/941816/

Эдгар Сипки рассказывает о вечной боли — gRPC прекрасен для микросервисов, но не очень то дружит с браузерами.

Причина: браузеры не умеют работать с HTTP/2 стримами из JavaScript. За 10 лет было 4 серьёзных попытки это исправить, и самая первая до сих пор остаётся самой адекватной.

История про gRPC-Gateway (2015):

- Японская разработчица Yuki Yugui Sonoda придумала гениально простое решение: не надо тащить gRPC в браузер, давайте сделаем прокси

- Добавляешь в proto-файлы HTTP-аннотации, генерируешь код — получаешь REST API для фронта и gRPC для бэкенда

- Вся бизнес-логика пишется один раз, интерсепторы работают

- Стримы тоже работают... через WebSocket (ну хоть так)

- Бонусом идёт автоматическая генерация Swagger-документации

Результат: это не настоящий gRPC в браузере, а "REST с протобафами". Но работает, и это главное.

————

Забавно, что такой большой Google так и не смог придумать ничего лучше, чем решение одного разработчика из 2015 года. Хотя, автор статьи как раз предполагает, что у Гугла были свои внутренние наработки:

Кстати, взял небольшое интервью (ну как интервью, в линкеде спросил) и она еще рассказала, что когда проект возымел успех, с ней связались ребята из Google и предложили как раз воспользоваться описанием спеки из своей механики, что уже как бы говорит, что google имели схожий проект, но так и не зарелизили его в OpenSource


Бонус для меня: благодаря статье узнал, что автор gRPC-Gateway — японка, будет что почитать теперь для практики языка.

#article #grpc #web
🔥11👍54
👴 Отдельный канал — defer Read()

Как вы знаете, в текущем канале я придерживаюсь правила: делюсь только теми материалами, с которыми сам ознакомился, и всегда добавляю комментарий со своим мнением.

Мне по-прежнему нравится такой подход, но порой он меня ограничивает. Я часто нахожу что-то интересное, но не всегда есть время глубоко вникнуть, дать оценку и написать вдумчивый комментарий.

🟢 Поэтому я завёл defer Read() — эдакий канал-радар или буфер для интересного контента, который попадается быстрее, чем я успеваю его переварить:

— Статьи, которые выглядят интересными, но пока не осилил

— Утилиты или проекты, которые заинтриговали — хочется поиграться, пощупать самому

— Прочие материалы из моих 50+ открытых вкладок 😩

🟠Во всяком случае, это будет не канал-помойка, а отфильтрованный поток — туда попадает только то, что прошло мой внутренний "code review" на интересность.

Также я буду добавлять по каждому материалу небольшой TLDR с пояснением что это и кому может пригодиться. С той лишь разницей, что это будут выводы, сделанные по беглому обзору или по LLM-выжимке.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🤔5🤯21
Testing Time: тестируем асинхронный код без time.Sleep в Go 1.25

Пост про testing/synctest в официальном блоге разработчиков Go

- Оригинал
- Хороший перевод

Go Team наконец-то решили давнюю проблему тестирования конкурентного кода. В 1.24 вышел экспериментальный пакет testing/synctest, а в 1.25 он стал стабильным.

Очень краткая суть: запускаешь тест в "пузыре" с фейковым временем и ждёшь, пока все горутины станут "устойчиво заблокированными" — то есть могут быть разблокированы только другими горутинами из того же пузыря.

Проблема стара как мир:

- Тестируешь context.WithDeadline — либо ждёшь реальную секунду (медленно), либо не ждёшь достаточно (тест нестабилен, флапает)

- Добавляешь time.Sleep с запасом — тест тормозит

- Убираешь запас — тест падает на CI под нагрузкой

Классический выбор: slow or flaky, pick... one!

Решение — пузырь с двумя функциями:

- synctest.Test(t, func(t *testing.T) {...}) — запускает функцию в пузыре с фейковым временем

- synctest.Wait() — ждёт, пока все горутины в пузыре станут "durably blocked"

- Время идёт только когда все заблокированы, вычисления занимают 0 времени

- Начало эпохи: полночь 1 января 2000 UTC (как в Go Playground)

Пример до/после:
// Было: медленно и ненадёжно
time.Sleep(time.Until(deadline) + 100*time.Millisecond)

// Стало: быстро и стабильно
synctest.Test(t, func(t *testing.T) {
time.Sleep(time.Until(deadline))
synctest.Wait()
})


————

Мне понравилось, что автор также рассказывает про историю создания. Сначала пытались добавить поддержку тестирования прямо в http-пакет — не вышло, особенно с HTTP/2. Потом сделали грязный хак с парсингом runtime.Stack() — работало, но стыдно показать. В итоге добавили поддержку прямо в рантайм.

Из ограничений: не работает с реальной сетью (вместо этого нужно использовать их имитацию в памяти — in-memory fake), мьютексы не считаются durably blocking, syscalls и cgo тоже. Но для 95% кейсов — самое то.

Забавно, что самый первый пример в статье — тест для context.WithDeadline. Видимо, это была та самая боль, с которой всё началось 🙃

#go1_25 #go_official #testing #concurrency
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍5🔥5
🧪 Сравнение инструментов для генерации моков

https://habr.com/ru/companies/avito/articles/939388/

Семён Эйгин из Авито (мейнтейнер minimock) сравнивает три популярных инструмента для генерации моков:

- mockery
- gomock
- minimock

Очевидно, автор предвзят, но статья всё равно интересная. Просто учитывайте это во время чтения.

Какие проблемы обсуждаются:

1. Типизация параметров

- mockery и gomock используют interface{} в ожиданиях: GetUser(1) интерпретируется как int вместо int64
- minimock генерирует строго типизированные методы: Expect(id int64)
- На практике: можно пропустить ошибку в стиле (int64=1) != (int=1)

2. Контроль количества вызовов

- gomock по умолчанию разрешает только один вызов метода
- mockery и minimock позволяют неограниченные вызовы
- Двойственная ситуация: gomock помогает поймать лишние вызовы, но требует явного Times() или AnyTimes()

3. Тестирование асинхронного кода

- mockery: приходится встраивать каналы через RunAndReturn — плохо масштабируется
- gomock: нужен самописный хелпер с controller.Satisfied()
- minimock: встроенная поддержка через mc.Wait(timeout)

————

Выбор автора, предсказуемо — minimock как "самый простой и топорный, покрывающий 99% случаев".

И я в целом согласен: строгая типизация экономит время на дебаге, встроенная поддержка асинхронности избавляет от костылей.

Хотя, я не отношусь к выбору моков настолько же серьёзно — я сам всё ещё использую mockery, потому что описанные его минусы не столь существенны, чтобы мне захотелось взять и перейти на что-то другое.

#article #testing #mocks
50👍12🤔2
Bubble Tea — TUI-фреймворк для Go

https://habr.com/ru/articles/939574/

Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.

#article #tui
👍11🔥8
Golang Дайджест
Bubble Tea — TUI-фреймворк для Go https://habr.com/ru/articles/939574/ Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.…
🦄 Экосистема Charm: полезные инструменты для терминала

Раз уж на то пошло, советую обратить внимание вообще на все проекты Charm, там много интересного. Например:

- Bubbles — готовые компоненты для Bubble Tea: текстовые поля, списки, таблицы, прогресс-бары, спиннеры.

- Lip Gloss — библиотека стилей для терминальных приложений. Цвета, рамки, отступы, выравнивание — всё как в CSS, только для консоли. Используется как база для Bubble Tea.

- Gum — эдакий мост между Bubbles / Lip Gloss и shell-скриптами. То есть, можно делать те же красивые скрипты, но без кода на Go.

- Glow — рендеринг Markdown прямо в терминале с подсветкой синтаксиса и красивым форматированием. Можно читать README не выходя из консоли.

- VHS — записывает GIF/видео демонстраций терминальных приложений через простой скрипт. Идеально для документации и README.

- Soft Serve — self-hosted Git-сервер с TUI интерфейсом. Можно красиво смотреть репозитории, коммиты и файлы прямо через SSH

Ну и наше любимое:
- Crushкрасивый консольный ИИ-агент . Поддерживает разные LLM (Claude, GPT, Gemini), использует LSP для контекста как в IDE, можно переключаться между моделями на лету.

Это только самое интересное, но там ещё много всякого. Советую пройтись по всему списку проектов и ознакомиться с каждым.

Вся экосистема построена вокруг идеи: терминал может быть красивым и удобным. И у них это отлично получается

Ну да, люблю я свистелки и перделки, теперь вы знаете обо мне всё 💅

Теперь подумываю сделать большое обзорное видео про всё это. Будет ли вам такое интересно?

#cli #tui
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍18🔥41
🐳 Container-aware GOMAXPROCS: Go наконец-то видит лимиты контейнеров

Пост в официальном блоге разработчиков Go, где они подробно рассказывают суть проблемы и как устроено недавнее техническое решение.

Go Team решили давнюю проблему совместимости с контейнерами. До версии 1.25 Go определял все ядра хоста, не учитывая CPU limits контейнера. Теперь GOMAXPROCS выставляется в соответствии с лимитами автоматически.

Суть проблемы:

- Контейнеру выделено 2 CPU на машине с 128 ядрами
- Go видит 128 ядер, создаёт кучу тредов
- Linux throttling тормозит приложение каждые 100ms
- Tail latency растёт

Что изменилось в 1.25:

- Go читает cgroup CPU limits и ставит GOMAXPROCS по ним
- Динамически обновляется при изменении лимитов
- Работает из коробки — просто обновите go.mod
- CPU requests игнорируются (только limits)

————

Наконец-то.. Проблеме много лет, и всё это время приходилось костылить через uber/automaxprocs или ENV-переменные. А теперь оно работает из коробки, как и должно было уже давно.

P.S. В Java эту проблему решили ещё в 2017 году 😩

#go1_25 #go_official #kubernetes #docker
Please open Telegram to view this post
VIEW IN TELEGRAM
20🔥18🤯2🤔1
Николай Тузов
🥂Выпуск про Go 1.25 уже доступен / GoGetPodcast 17 https://youtu.be/fHuJNsZPCJ0 Этого ролика вам точно будет достаточно для полного понимания нововведений, вне зависимости от вашего опыта Подробно обсудили, что нового в новой версии, зачем это нужно, как…
🥂Что нового в Go 1.25 — глубокий разбор изменений / GoGetPodcast

https://youtu.be/fHuJNsZPCJ0

Этого ролика вам точно будет достаточно для полного понимания нововведений, вне зависимости от вашего опыта

Подробно обсудили, что нового в новой версии, зачем это нужно, как оно устроено, в сложных местах делали ликбез для лучшего понимания изменений.

Дима был очень хорош, такого подробного и глубокого разбора вы больше нигде не увидите, а с комментариями Глеба оно ещё круче, очень рекомендую.

#gogetpodcast #podcast
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍63
Forwarded from Go Update
🏗️ gogrep — инструмент для семантического поиска внутри вашей кодовой базы. 🏗️

Наверняка много кому приходилось сталкиваться с ситуацией «надо по коду найти вызовы по определенному паттерну». Чаще всего для этого мы используем регулярные выражения (grep, ag, rg). Однако у них всех есть один минус — они интерпретируют файлы как текст, а не как код. Из-за этого в результаты поиска попадают как нужные нам места вызова, так и комментарии, участки текста и прочая.

Решение этой проблемы: семантический поиск. Это когда утилита разбивает файл на синтаксическое дерево и производит поиск уже по самому дереву. Приведу простой пример:

~/mws/api > gogrep . 'ptr.Get($_)'


Здесь мы явно говорим: найди все вызовы, у которых слева есть идентификатор ptr а внутри вызова идет только один аргумент (не важно выражение, их сумма, или переменная). Таким образом мы идентифицируем именно конкретные места которые будут частью компилируемого кода.

Документация по gogrep доступна тут. С описанием синтаксиса немного сложнее: большую (и лучшую) часть информации по мэтчингу и по фильтрам можно найти в тестах. Сама тулза является часть куда более мощной тулзы go-ruleguard (которая кстати входит в golangci-lint).

За обе утилиты огромнейшее спасибо Искандеру Шарипову.
🔥11👍1
Go Update
🚀 Расширение функции new для создания указателя на значения 🚀 Отличные новости! Предложение, обсуждение которого которого длится уже больше четырех лет и которое выдвинул сам Роб Пайк, наконец-то подходит к принятию. В чем суть: есть у нас встроенная функция…
Наконец-то можно будет выкинуть из проектов мой "любимый" lo.ToPtr()

Правда остаётся ещё lo.FromPtr(), но надежда уже есть.

Если что, мне жутко не нравится идея тащить в проект samber/lo, но не всегда удаётся с этим бороться. При этом, я даже не знаю что хуже — тащить этого монстра ради пары строк кода, или же желание использовать ещё больше его функционала 😩

К слову, в предыдущем выпуске подкаста тема `lo` очень подробно обсуждалась
в самом конце. Советую послушать, если нужны аргументы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥32
Forwarded from Go Update
✔️ errors.AsType — типобезопастная замена errors.As ✔️

Тем временем, в 1.26 нас (вероятно) ждет еще одно приятное изменение: дженерики наконец доберутся до пакета errors.

Все изменение проще описать тремя строчками кода. В 1.25 у нас вот так:


var pe *fs.PathError
if errors.As(err, &pe) {
fmt.Println("Failed at path:", pe.Path)
}


А в 1.26 можно будет вот так:


if pe, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("Failed at path:", pe.Path)
}


Вроде и небольшое изменение, но оно ведет, как минимум, к двум положительным вещам:
• Зона видимости типизированной ошибки во многих участках у нас теперь будет меньше, а значит меньше захламляется пространство имен и снижается необходимость думать над правильным именем для ошибки.
• В отличии от errors.As, который вторым аргументом принимал any, новая функция принимает только тех, кто реализует интерфейс error. Несмотря на то, что у нас есть проверка внутри go vet проверяющая второй аргумент у As, всегда приятнее когда компилятор может самостоятельно поймать ошибку на этапе сборки приложения.

Кстати, причина по которой сигнатура текущей функции выглядит как As(err error, target any) bool заключается в том, что указатель на интерфейс и указатель на тип реализующий интерфейс для компилятора две несовместимые конструкции. Иначе говоря, вот такой код


func As(err error, target *error) bool {
panic("unimplemented")
}



pe *fs.PathError
if As(err, &pathError) {
fmt.Println("Failed at path:", pathError.Path)
}





компиляцию не пройдет. А причина в том, что интерфейсы у нас это отдельная сущность которая существует не только во время компиляции, но и во время выполнения.
🔥263
Forwarded from go-with-me
⚡️ Concurrency Patterns. Fan In
В предыдущем посте мы немного напутали с определением такого многопоточного паттерна как Fan Out

На деле мы показывали Tee, который распространяет одно и то же значение V из канала-источника на N каналов-потребителей

Отличие Fan Out от Tee в том, что на N каналов распространяются разные значения из одного канала-источника. Тобишь, воркеры тянут значения из одного канала, борясь за них насмерть

Лирическое отступление закончено, наша совесть чиста, а сегодняшняя тема будет посвящена Fan In

Этот паттерн является обратным для Fan-Out. Мы собираем данные из нескольких каналов-источников и направляем их в один общий канал-потребитель


1. Default
Итак, что мы имеем?
— Есть воркеры — они кладут значения в N каналов и являются продьюсерами
— Каждый из этих N каналов будет получать значения от своего продьюсера. Назовем такие каналы "стоковыми"
— Есть один общий канал out, туда будет нужно отправить все значения из стоковых каналов
— Для этого мы запускаем N потоков, каждый из которых слушает свой стоковый канал, куда кладет значения продьюсер и редиректит все значения в out

Playground пример

Но что же будет, если какой-то наш продьюсер потух и больше не шлет никаких значений, а передаггый контекст не отменен? Как бы нам понять, что воркер не является активным и перезапустить его? — в этом нам поможет такой механизм как "Heartbeats"

Heartbeat — это регулярное сообщение от продьюсера/воркера, подтверждающее, что он жив и работает


2. Heartbeats
Приступим к рассмотрению этого чуда!

Основная идея проста:
— Имеем структуру, которая хранит в себе стоковый канал, используемый как пайп между воркером и стоком, и канал "сердцебиений"
— Функция Supervise ответственна за отслеживание "сердцебиений" и перезапуск воркера при их отсутствии по TTL
— Функция FanIn принимает на вход стоковые каналы и возвращает результирующий канал, из которого можно читать данные

Всмотримся в наши функции поподробнее

2.1. FanIn
— Не отклоняемся от цели: выкачиваем данные из стоковых каналов и перекладываем в out, реагируя на контекст и неблокирующе отправляя "сердцебиение" нашему супервизору, который пристально наблюдает за нашими воркерами
WaitGroup здесь так же используется для того, чтобы дождаться конца работы наших стоков и отдать управление основному потоку
после дренажа всех "живых" значений

2.2 Supervise
— Создаем стоковый канал и канал "сердцебиений", агрегируем эти значения в структуре Source и возвращаем ее
— В отдельном потоке запускаем нашу рутину по отслеживанию и перезапуску воркеров

2.2.1 Смотрим на внутренности запущенного потока внутри Supervise
— Изначально происходит создание дочернего контекста с отменой для нашего воркера. Этот контекст будет рулить в тот момент, когда наш TTL пройдет и надо будет потушить воркера
— Создаем ticker, который будет слать ивенты, семантически значащие следующее: "в нашего воркера стреляли и он упал в лужу на..."
После получения ивента мы отменяем контекст и воркер окончательно "задыхается в луже"
— Первично запускаем работягу в отдельном потоке
— Если ловим ивент от тикера: производим отмену контекста, переназначаем этот же контекст и функцию отмены, сбрасываем таймер, и запускаем нового воркера в отдельном потоке
— В случае, когда из стокового потока нам пришло "сердцебиение" мы просто сбрасываем таймер и движемся дальше!

Стоит отметить, что воркеры должны "реагировать" на переданный контекст. Без этого мы получим утечку потоков и черт его знает, чем нам это грозит (профилированием и
устранением проблемы, которой можно было бы и избежать)

Таким образом, мы получаем более надежный Fan In, где все источники данных контролируемы и восстанавливаемы при зависаниях

Playground пример


Статью писали с Дашей: @dariasroom

Stay tuned 😏
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍96🔥2🤯1
conc — удобные примитивы для конкурентного кода

https://github.com/sourcegraph/conc

⭐️ ~10.1k

Небольшая библиотека от Sourcegraph, которая предлагает более безопасные и удобные обёртки над стандартными инструментами конкурентности в Go.

Впервые встретил её на своей текущей работе, и в целом мне понравилось, поэтому грех не поделиться.

Что в ней есть интересного:

- conc.WaitGroup — альтернатива стандартному sync.WaitGroup: ловит паники в горутинах и возвращает их в Wait(), а также не даёт забыть вызвать Wait()

- pool — конкурентный пул задач с ограничением числа горутин (WithMaxGoroutines), сбором ошибок (WithErrors, WithFirstError) и отменой задач при ошибках (WithContext)

- stream — параллельное выполнение задач с сохранением порядка результатов (удобно, когда порядок важен, но хочется параллелизма)

- iter.Map / ForEach — упрощённые хелперы для конкурентной обработки слайсов

🟠 Библиотека пока pre-1.0 (последний релиз в феврале 2023), API может меняться.

#library #concurrency #goroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍10🤯1
📆Go-разработка в 2025 году — как оценить ситуацию на рынке и в индустрии?

Как меняется стек, какие практики и инструменты становятся стандартом, как работают команды и какие задачи сейчас на передовой?

Ответить на эти и многие другие вопросы можно только одним способом — провести исследование: опросить как можно больше специалистов, обработать данные и показать результаты в удобном формате.

Именно этим уже несколько лет подряд занимается команда DevCrowd. И они снова запускают ежегодное исследование русскоязычных Go-разработчиков.

🟢От себя честно скажу: ребята делают очень классную и важную работу для нашего сообщества.
Посмотрите
прошлое исследование — там очень много интересных и полезных данных, но читается всё это очень легко, благодаря шикарной подаче.
Поэтому я считаю, что проект обязательно нужно поддержать.


Присоединяйтесь — помогите собрать честный и актуальный срез профессии.
Не забудьте там упомянуть и мой канал, если он вам нравится, для меня это очень важно ❤️

Зачем участвовать?

– Сравните свои задачи, подходы и процессы с коллегами
– Узнаете, какие технологии и практики в ходу у коллег
– Получите ориентиры для развития и найма
– Сделаете профессию Go-разработчика прозрачнее для сообщества и рынка

📊 Результаты исследования будут в начале ноября на devcrowd.ru
Заполнение не долгое, займёт ~10 минут

🫶 Пройти опрос

👴 Результаты прошлого года

#devcrowd #research
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍32🤯1