Библиотека Go для собеса | вопросы с собеседований
7.36K subscribers
256 photos
10 videos
1 file
737 links
Вопросы с собеседований по Go и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/0b524a15

Для обратной связи: @proglibrary_feeedback_bot

Наши каналы: https://t.me/proglibrary/9197
Download Telegram
Зачем может понадобиться context.WithoutCancel

context.WithoutCancel нужен, когда у вас есть операция, которая обязана завершиться независимо от того, был ли отменён родительский контекст.

Типичная проблема без него:
func handleRequest(ctx context.Context) {
doWork(ctx)
saveAuditLog(ctx) // ctx уже отменён — лог не запишется!
}


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

Вот так это можно обойти:
func handleRequest(ctx context.Context) {
doWork(ctx)

safeCtx := context.WithoutCancel(ctx)
saveAuditLog(safeCtx) // выполнится в любом случае
}


WithoutCancel создаёт копию контекста, которая наследует values и deadline, но игнорирует отмену родителя.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Что произойдёт, если вызвать context.AfterFunc на уже отменённом контексте

Функция выполнится немедленно в новой горутине, без ожидания. Проверять состояние контекста заранее не нужно, AfterFunc сам это обрабатывает.

ctx, cancel := context.WithCancel(context.Background())
cancel() // уже отменён

context.AfterFunc(ctx, func() {
fmt.Println("Runs immediately")
})


🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Нужно ли лочить структуру мьютексом, если идёт конкурентная запись в разные поля

Короткий ответ — да. Структуры в Go не потокобезопасны по умолчанию. Даже если две горутины пишут в разные поля, без синхронизации возникает гонка данных.

type Data struct {
Field1 int
Field2 int
mu sync.Mutex
}

// горутина 1
d.mu.Lock()
d.Field1 = i
d.mu.Unlock()

// горутина 2
d.mu.Lock()
d.Field2 = i
d.mu.Unlock()


Мьютекс гарантирует, что в любой момент только одна горутина имеет доступ к структуре. Без него поведение программы непредсказуемо — go race detector это подтвердит.

Обойтись без мьютекса можно только если поля полностью независимы и нет никаких побочных эффектов. Но это требует уверенности в контексте, а не предположений.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔81😢1🌚1
Самый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов

Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.

В программе:

— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками LangGraph, AutoGen, MCP и CrewAI;
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.

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

Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.


Ах да, чуть не забыли! Дарим промокод AGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁

Стать AI-инженером
😁2
Что возвращает context.AfterFunc и как отменить запланированную функцию

AfterFunc возвращает функцию stop(). Если вызвать её до того, как коллбэк начал выполняться, он будет отменён.

stop := context.AfterFunc(ctx, func() {
// cleanup
})

if stopped := stop(); stopped {
fmt.Println("Callback cancelled before execution")
}


stop() возвращает true — функция остановлена до запуска.
stop() возвращает false — функция уже выполняется или была остановлена ранее.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
Что может остановить горутину

time.Sleep(d) — усыпляет горутину на нужное время. Классика, когда надо подождать.

runtime.Gosched() — временно приостанавливает текущую горутину и передаёт управление планировщику, чтобы другие горутины могли выполниться.

runtime.Goexit()
— завершает горутину немедленно, но аккуратно: все defer-ы выполнятся перед выходом.

Блокировка на канале — горутина ждёт, пока кто-то не отправит или не прочитает данные. Естественная синхронизация.

sync.Mutex — вызов Lock() блокирует горутину, пока мьютекс занят кем-то другим. Защита общих данных.

context.Context — горутина слушает ctx.Done() и останавливается, когда контекст отменяется или истекает таймаут.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👏4😁2😢1
Как вам вопросы прошедшей недели

Оцените их по шкале 🔥,❤️,👍,😢, 🥱,
где 🔥 — это супер, а 🥱 — это скучно.

Также приветствуется фидбек в комментах.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
11🔥10👍7
Что такое unique.Handle и зачем он нужен

unique.Handle[T] — это обёртка над значением типа T, которая гарантирует что два одинаковых значения всегда дадут один и тот же Handle. Это позволяет сравнивать значения через == вместо reflect.DeepEqual или побайтового сравнения.

import "unique"

h1 := unique.Make("hello")
h2 := unique.Make("hello")

fmt.Println(h1 == h2) // true — один и тот же указатель внутри


🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9
Кажется, мы окончательно перешли от игрушек к суровому AgentOps

Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.

На курсе мы:

— пошагово строим готовые системы на LangGraph, CrewAI и MCP;
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.

В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.

Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.


Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!

Зафиксировать цену и перейти к сборке своих агентов
2😁1
Почему GOPATH уступил место Go модулям

GOPATH просто брал тот код, что уже лежал на вашей машине. Склонировали проект на другом компьютере — и зависимости уже другие. Воспроизводимость сборки не гарантирована.

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

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👾1
Какие типы можно передавать в unique.Make

Только comparable типы, которые поддерживают ==. Срезы, мапы и функции не подойдут, компилятор не пропустит.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
Почему interface{} или any замедляют программу

Любой интерфейс в Go — это два указателя. Пустой интерфейс (eface) хранит указатель на метаданные типа и указатель на данные. Непустой (iface) — указатель на itab (таблицу с информацией о типе и методах) и указатель на данные.

Само по себе это не проблема. Проблемы возникают из-за последствий такого устройства.

Когда вы передаёте конкретное значение в интерфейс, компилятор запускает escape analysis — анализ, может ли значение убежать за пределы текущего стекового фрейма. Если да, значение копируется в кучу, а указатель смотрит на эту копию.

Простые типы: int, bool, указатели; компилятор нередко передаёт без аллокации. Но структуры и значения, которые реально убегают, аллоцируются. Это означает нагрузку на GC.

Вызов метода через интерфейс это косвенный вызов через itab.fun[].

Компилятор не знает во время компиляции, какая именно функция будет вызвана, поэтому:

• Компилятор не может подставить тело функции на месте вызова

• Процессор видит косвенный переход и не может надёжно его предсказать

• Перед вызовом нужно прочитать адрес функции из itab

Это не катастрофа при редких вызовах, но в циклах с миллионами итераций разница ощутима.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8🤔3
В чём разница между unique.Handle и простым указателем

Указатель не даёт гарантии уникальности. Два разных указателя могут указывать на равные значения, но == вернёт false.

Handle
гарантирует что равные значения всегда один и тот же Handle.

s1 := "hello"
s2 := "hello"

p1 := &s1
p2 := &s2

fmt.Println(p1 == p2) // false — разные адреса

h1 := unique.Make(s1)
h2 := unique.Make(s2)

fmt.Println(h1 == h2) // true — одно интернированное значение


🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
В чем преимущество iter.Seq перед использованием каналов для обхода коллекций

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

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

Функции-итераторы работают в том же стеке и в той же горутине, что и основной цикл for. Это исключает затраты на синхронизацию и переключение контекста, делая обход практически таким же быстрым, как обычный цикл по слайсу. При этом механизм yield гарантирует, что итератор корректно завершится, как только цикл будет прерван через break или return.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Начать рассказывать интервьюеру, как вы ловко дёргаете ручки API через базовый LangChain.

Звучит как отличный план, да? Нет, это мгновенный отказ.

В свежем отчёте по рынку GPU говорится, что 54% компаний стопают ИИ-внедрения тупо из-за конских затрат на инфраструктуру. На серверах более 70% стоимости — это видеокарты. Поэтому на собесах сейчас спрашивают не про красивые промпты, а про жёсткую экономику агентов.

По сути, от вас ждут понимания, как лимитировать ресурсы на лету, роутить запросы и дебажить отказы через механизм time-travel в LangGraph. Если вы до сих пор собираете ботов в ноутбуках, гляньте обновлённый курс «Разработка ИИ-агентов» — фокус там смещён с игрушечных концепций на суровый энтерпрайз.

Что требуют от мидлов и выше:

— интеграция мультиагентных систем по стандарту MCP;
— суровый AgentOps: метрики, трейсинг, защита от деградации пайплайнов;
— локальный деплой Open Source под 152-ФЗ (без этого в финтех можно даже не стучаться).

Прямо сейчас можно урвать курс с увесистой скидкой (49 000 ₽ 62 990 ₽ за базовый тариф и 99 000 ₽ 124 990 ₽ за продвинутый трек), но стоит поторопиться — на потоке осталось всего 5 мест.

👉 Подтянуть архитектуру до уровня прода
🥱3😁1
В чем основная идея пакета bufio и какую проблему он решает

Стандартные интерфейсы io.Reader и io.Writer при каждом вызове Read или Write обычно инициируют системный вызов. Системные вызовы обходятся дорого, так как требуют переключения контекста между пространством пользователя и ядром ОС.

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

Аналогично bufio.Writer накапливает данные и записывает их в целевой объект одним большим блоком, когда буфер заполняется или принудительно сбрасывается.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94
Как переиспользовать буферы в bufio для экономии памяти

В высоконагруженных системах постоянное создание новых bufio.Reader/Writer создает нагрузку на сборщик мусора. Вместо создания нового объекта для каждого нового HTTP-запроса или файла, можно использовать метод Reset(io.Reader).

Этот метод позволяет взять старый экземпляр bufio.Reader, подставить в него новый источник данных и продолжить работу, используя тот же самый массив памяти в качестве буфера. Это идеальный кандидат для совместного использования с sync.Pool.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Где чаще всего хранится значение Go без указателя, объявленное как локальная переменная

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

Это возможно потому, что компилятор заранее знает время жизни переменной: она живёт ровно столько, сколько выполняется функция. Никакой внешней системы управления памятью для этого не нужно.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
4👾1
Почему выделение памяти на стеке эффективнее, чем на куче

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

В случае кучи ни компилятор, ни среда выполнения не могут точно предсказать, когда память станет ненужной, поэтому нужен сборщик мусора, который регулярно сканирует кучу и освобождает объекты. Это дороже и создаёт паузы.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
Что делает OnceValue и зачем он нужен

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

Результат кэшируется и возвращается при всех последующих вызовах. Используется для ленивой и дорогостоящей инициализации.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Что произойдёт с памятью, которую держит OnceValue, если обёртка больше не используется

Обёртка это замыкание, которое держит ссылки на once, result и f. Пока есть хотя бы одна ссылка на обёртку, GC не освободит эти данные. Если f тяжёлая инициализация, например, загрузка большого файла, а обёртка живёт в глобальной переменной, то данные живут вечно.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1