Библиотека Go для собеса | вопросы с собеседований – Telegram
Библиотека Go для собеса | вопросы с собеседований
7.02K subscribers
254 photos
10 videos
1 file
630 links
Вопросы с собеседований по Go и ответы на них.

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

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

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

Наши каналы: https://news.1rj.ru/str/proglibrary/9197
Download Telegram
Что такое Cache Contention

Допустим, у вас есть структура со счётчиками, которые обновляют разные горутины:
type Counters struct {
a int64
b int64
c int64
}


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

Проблема в том, как устроен кеш процессора. CPU не читает отдельные переменные — он загружает данные кеш-линиями по 64 байта. Все три поля структуры попадают в одну линию.

Когда горутина на одном ядре изменяет поле a, процессор инвалидирует эту кеш-линию на всех остальных ядрах. Другое ядро хочет изменить b — ему приходится заново загружать линию из памяти. И так по кругу.

Это и есть Cache Contention, или false sharing — ядра конкурируют за кеш-линию, хотя работают с разными данными.

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Как глубоко доходит отмена контекста

Отмена в Go всегда течёт сверху вниз: как только отменяется родительский контекст, автоматически отменяются все его дочерние контексты на любом уровне вложенности.

Обратного эффекта нет: отмена дочернего контекста не затрагивает родителя и других веток, только эту конкретную часть.

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

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

Использовать пакет strconv:
// Строка → int
num, err := strconv.Atoi("42")

// int → строка
str := strconv.Itoa(42)

// Для других типов:
i64, _ := strconv.ParseInt("42", 10, 64) // string → int64
str64 := strconv.FormatInt(42, 10) // int64 → string


Atoi возвращает ошибку, если строка не число — проверяйте err

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩3
Как встроить профайлер в приложение

В Go есть пакет net/http/pprof, который при импорте автоматически регистрирует HTTP-обработчики для сбора метрик. Обычно профайлер запускают на отдельном порту, чтобы не смешивать с основным API.

import (
"net/http"
_ "net/http/pprof" // подчёркивание означает импорт ради side-effect
)

func main() {
// Запускаем профайлер в отдельной горутине на порту 6060
go func() {
http.ListenAndServe(":6060", nil)
}()

// Здесь основная логика приложения...
}


После запуска становятся доступны эндпоинты для анализа:

/debug/pprof/profile — нагрузка на процессор
/debug/pprof/heap — использование памяти
/debug/pprof/goroutine — состояние горутин
/debug/pprof/block — блокировки

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Как корректно посчитать количество символов в строке

Функция len() возвращает размер в байтах, а не в символах. Для Unicode-текста это критически важно.

Кириллица кодируется в UTF-8 двумя байтами, китайские иероглифы — тремя, а emoji, например, может занимать до четырёх байт. Поэтому для подсчёта символов нужно использовать utf8.RuneCountInString().

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤩1
Сколько памяти занимает слайс

Заголовок слайса занимает 24 байта на 64-битной системе. Это фиксированный размер независимо от содержимого.

Внутренняя структура слайса выглядит так:
type slice struct {
array unsafe.Pointer // 8 байт — указатель на underlying array
len int // 8 байт — текущая длина
cap int // 8 байт — ёмкость
}


24 байта — это только заголовок. Сами данные хранятся отдельно в массиве, на который указывает array.

Пример расчёта общего размера:
s := make([]int64, 100) 
// Заголовок: 24 байта
// Данные: 100 * 8 = 800 байт
// Итого: 824 байта


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

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Можно ли закрыть канал со стороны читателя

В Go есть правило: канал закрывает только отправитель. Если читатель закроет канал, а отправитель попытается записать в него данные — программа упадёт с паникой.

Паника при записи в закрытый канал — это не баг, а защита от гонок данных. Отправитель точно знает, когда закончил отправлять. Читатель — не знает.

Но технически читатель закрыть канал может.

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

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

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

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

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍9🔥8😢2
Как отправителю правильно закрыть канал

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

После получения сигнала, отправитель может корректно закрыть основной канал данных:
func main() {
dataCh := make(chan int)
stopCh := make(chan struct{})

go func() {
for {
select {
case data, ok := <-dataCh:
if !ok {
// Канал закрыт, прекращаем обработку
return
}
// Обработка данных
fmt.Println(data)
case <-stopCh:
// Получен сигнал остановки, закрываем канал dataCh
close(dataCh)
return
}
}
}()

// Отправка данных в канал
dataCh <- 1
dataCh <- 2

// Отправка сигнала остановки
stopCh <- struct{}{}
}


🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
😁43🤔1
Как писать обёртки для фаззинг-тестов в Go

Фаззинг-тест начинается с func Fuzz и принимает *testing.F:
func FuzzParse(f *testing.F) {
// Seed-корпус
f.Add("valid input")
f.Add("edge case")

// Фаззинг-функция
f.Fuzz(func(t *testing.T, input string) {
result, err := Parse(input)
if err != nil {
return // Ошибка — нормально
}
// Проверки инвариантов
if result == nil {
t.Error("результат не должен быть nil при отсутствии ошибки")
}
})
}


Часто тестируемая функция принимает сложные типы, а фаззер работает только с базовыми: string, []byte, int, bool и несколькими другими. Обёртка конвертирует примитивы в нужные структуры:
func FuzzUserValidation(f *testing.F) {
f.Add("john@example.com", 25, true)

f.Fuzz(func(t *testing.T, email string, age int, active bool) {
// Обёртка: преобразуем примитивы в структуру
user := User{
Email: email,
Age: age,
Active: active,
}

err := ValidateUser(user)
// Проверяем инварианты
if age < 0 && err == nil {
t.Error("отрицательный возраст должен вызывать ошибку")
}
})
}


🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Зачем нужен CGO_ENABLED=0 при сборке Go-приложений

Флаг CGO_ENABLED=0 вырубает CGo на этапе компиляции — ваш код собирается полностью на чистом Go, без единой строчки из C-библиотек.

При CGO_ENABLED=1 компилятору нужны C-тулчейн и хедеры для целевой платформы. С CGO_ENABLED=0 просто делаете GOOS=linux GOARCH=arm64 go build — и готово, бинарник для любой архитектуры собран за секунды.

Можно использовать минималистичные образы типа scratch или distroless — приложение запустится даже в контейнере без единой установленной библиотеки.

Убирая C-код, вы автоматически избавляетесь от целого класса уязвимостей: buffer overflow, use-after-free и прочих радостей ручного управления памятью. Плюс код становится действительно платформонезависимым.

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Объясните систему пакетов в Go

Каждый .go файл стартует с декларации package название — это определяет, к какой логической группе относится код.

Пакет с именем main компилируется в исполняемый бинарник. Без main — это библиотеки для переиспользования в других проектах.

Никаких магических автоимпортов — каждую зависимость указываете руками: import "github.com/user/repo/pkg". Go-компилятор сразу видит все связи между модулями.

Простое, но мощное правило:

PublicFunc() — заглавная буква, доступна везде
privateFunc() — строчная буква, видна только внутри пакета

Это работает для всего: функций, типов, структур, переменных. Никаких ключевых слов public/private — компилятор смотрит только на первую букву.

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

Стандартная функция time.Sleep() в Go имеет существенный недостаток — она блокирует выполнение и не реагирует на сигналы завершения работы через context. Горутина замирает на указанное время, игнорируя любые попытки её остановить.

Вместо прямого использования time.Sleep() можно комбинировать select с time.After() и каналом контекста:
select {
case <-time.After(duration):
// Пауза завершилась естественным образом
case <-ctx.Done():
// Контекст отменён — немедленно выходим
return ctx.Err()
}


Такой подход позволяет горутине мгновенно реагировать на отмену контекста.

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
8😁1
«Этот манёвр будет стоить нам 51 год...»

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

В Proglib Academy поднимаются цены. У вас есть шанс зайти на обучение по старой стоимости:

— Разработка ИИ-агентов
— Математика для разработки AI-моделей
— ML для старта в Data Science
— Математика для Data Science
— Специалист по ИИ
— Алгоритмы и структуры данных
— Программирование на Python
— Основы IT для непрограммистов
— Архитектуры и шаблоны проектирования

Забрать базу для собеседований

⚠️ Цены вырастут уже 19 января
Какие основные сущности в планировщике в Go

Планировщик Go реализует модель M:N, где M горутин выполняются на N потоках ОС.

В его основе лежат три ключевые сущности:

G (Goroutines) — это потоки выполнения, основные единицы конкурентности в Go. Они значительно легче потоков ОС и могут создаваться тысячами.

M (Machines) — это потоки операционной системы, которые непосредственно исполняют код на физических ядрах процессора. Они выполняют горутины.

P (Processors) — логические процессоры, которые служат связующим звеном между G и M. Каждый P имеет локальную очередь готовых к выполнению горутин и управляет их распределением. Количество P обычно равно числу доступных ядер CPU.

Горутины хранятся в очередях выполнения— есть локальные очереди у каждого P и одна глобальная.

🎁 Новогодняя акция: 3 курса по цене 1
🤝
Помощь с выбором курса

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

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

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

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍5😢3🥱2🔥1
Что происходит при склеивании строк

Строки в Go неизменяемы. При использовании оператора «+» для конкатенации каждый раз создается новая строка в памяти. Это приводит к избыточным аллокациям и падению производительности при частых операциях склеивания.

Для построения строк используйте strings.Builder — он накапливает данные во внутреннем буфере и минимизирует выделение памяти.

Пример с strings.Builder:
var builder strings.Builder
for i := 0; i < 1000; i++ {
builder.WriteString("x")
}
result := builder.String()


🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤‍🔥4
Как можно получить дедлок при работе с горутинами

Deadlock возникает, когда все горутины заблокированы и ждут друг-друга, из-за чего программа не может продолжить выполнение. Рантайм обнаруживает это и завершает программу с ошибкой fatal error: all goroutines are asleep - deadlock!.

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

Примеры:
// Пример 1: отправка без получателя
ch := make(chan int)
ch <- 1 // deadlock - никто не читает

// Пример 2: чтение без отправителя
ch := make(chan int)
<-ch // deadlock - никто не пишет

// Пример 3: взаимная блокировка
var mu1, mu2 sync.Mutex
go func() {
mu1.Lock()
mu2.Lock() // ждет mu2
}()
mu2.Lock()
mu1.Lock() // ждет mu1


Используйте select с default или таймауты для предотвращения.

🐸Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
ЭТОТ ПОСТ СПАСЕТ ТВОЙ 👩‍💻-СОБЕС

В наше время очень тяжело попасть на собеседование! Поэтому предлагаем вам очень серьезно относиться к ним.
Не упускайте не единое собеседование, готовьтесь к каждому, как к последнему.
Регулярно проверяйте свои hard-skills.
Забирай чек-лист из закрепленного сообщения - 55 вопросов из реальных собесов!

P.S. помимо непосредственно GO, разбираем другие необходимые технологии, про них нельзя забывать!

Помни, что каждое собеседование в 2026 на вес золота!
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1🌚1
Зачем append возвращает слайс

append возвращает слайс, потому что операция добавления элементов может привести к реаллокации базового массива, если текущая capacity недостаточна.

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

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

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