Библиотека Go для собеса | вопросы с собеседований
6.88K subscribers
224 photos
8 videos
1 file
438 links
Вопросы с собеседований по Go и ответы на них.

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

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

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

Наши каналы: https://t.iss.one/proglibrary/9197
Download Telegram
💬 Почему важно следить за временем жизни горутин и как мы можем избежать проблем с утечкой памяти в Go?

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

📌 Чтобы избежать проблем с утечкой памяти, необходимо:

1. Использовать контексты (context.Context): контексты позволяют контролировать время выполнения горутины и отменять её выполнение, когда это необходимо. Например, использование select с контекстом позволяет горутине завершиться корректно при получении сигнала отмены:

func Job(ctx context.Context, d time.Duration) {
for {
select {
case <-ctx.Done():
return
default:
...
time.Sleep(d)
}
}
}


2. Закрывать каналы: если горутина читает данные из канала, важно корректно закрывать этот канал, чтобы горутина завершалась и не зависала бесконечно.

func worker(jobs <-chan int) {
for i := range jobs {
...
}
}

jobs := make(chan int)
go worker(jobs)
// Закрытие канала, когда работа завершена
close(jobs)


3. Избегать использования time.Sleep() без контекста: функция time.Sleep() не поддерживает прерывания и может привести к зависанию горутины, если её необходимо завершить. Вместо этого используйте конструкции, учитывающие контекст, такие как time.After с select.
👍82
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

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

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 Как отключить поддержку HTTP/2 на стороне клиента и сервера в Go? Почему это может понадобиться?

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

Для отключения HTTP/2 необходимо установить GODEBUG следующим образом:

export GODEBUG=http2client=0,http2server=0


Эта команда отключит поддержку HTTP/2 по умолчанию как в HTTP-клиенте, так и в HTTP-сервере. Это может быть полезно в случае, если есть проблемы с реализацией HTTP/2 на сервере или если необходимо поддерживать совместимость с более старыми системами, которые не поддерживают HTTP/2.

При запуске программы Go с такими параметрами GODEBUG, программа будет использовать только HTTP/1.1 для всех HTTP-запросов и ответов, обходя любые потенциальные проблемы, связанные с HTTP/2.

👉 Подробнее
👍141
💬 Почему лучше использовать неэкспортируемую пустую структуру в качестве ключа контекста в Go вместо строки или другого примитивного типа?

Использование неэкспортируемой пустой структуры в качестве ключа контекста в Go предпочтительнее по нескольким причинам:

1. Уникальность: пустая структура обеспечивает уникальность в пределах области видимости пакета, что помогает избежать конфликтов, которые могут возникнуть при использовании строк или других примитивных типов в качестве ключей.
2. Легковесность: пустая структура не выделяет памяти, так как она не содержит полей, что делает ее очень легким и эффективным вариантом для использования в качестве ключа.
3. Избежание конфликтов: использование пустых структур помогает избежать конфликтов с другими пакетами, которые могут случайно использовать те же самые строки или примитивные типы в качестве ключей контекста.

Пример кода с использованием пустой структуры:


type contextKey struct{}

func main() {
ctx := context.WithValue(
context.Background(),
contextKey{}, "данные, связанные с запросом",
)

handleRequest(ctx)
}

func handleRequest(ctx context.Context) {
fmt.Println("data:", ctx.Value(contextKey{}))
}


Этот пример демонстрирует, как использование пустой структуры в качестве ключа контекста помогает обеспечить уникальность и избежать потенциальных конфликтов.
👍162
💬 Почему в Go лучше использовать strconv вместо fmt для преобразования в/из строки?

Пакет strconv специально создан для преобразования строк, что означает, что он оптимизирован именно для них.

Для наглядности рассмотрим простое сравнение производительности:


func BenchmarkFmt(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprint(i)
}
}

func BenchmarkStrconv(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strconv.Itoa(i)
}
}

BenchmarkFmt-8 23821753 50.17 ns/op 16 B/op 2 allocs/op
BenchmarkStrconv-8 100000000 11.47 ns/op 3 B/op 1 allocs/op


strconv.Itoa значительно быстрее и эффективнее с точки зрения выделения памяти по сравнению с fmt.Sprint. fmt.Sprint при этом использует рефлексию, чтобы понять, с каким типом данных работает, и определяет лучший способ форматирования его как строки.

Процесс рефлексии не «бесплатный», он добавляет как время, так и накладные расходы на память, что может быть довольно значительным, когда мы обрабатываем большие объемы данных или требуется высокая производительность.
👍203
💬 Что произойдет, если в type switch использовать временную переменную для типа nil? Какой тип будет у этой переменной?

Когда в type switch используется временная переменная для типа nil, тип этой переменной будет таким же, как и тип исходного значения, которое мы проверяем в TypeSwitchGuard. Например, если исходное значение имеет тип any, временная переменная также будет иметь тип any. Это можно проиллюстрировать следующим примером:
var x any
var y error

switch t := x.(type) {
case nil:
y = t // Ошибка компиляции: any does not implement error
}

В этом примере код не компилируется с ошибкой, указывающей, что переменная типа any не может быть присвоена переменной типа error, так как тип any не реализует метод Error. Это подтверждает, что временная переменная t в случае nil имеет тот же тип, что и x (в данном случае any).
1
Ответьте на 3 вопроса, чтобы получить вводные занятия к курсу «Алгоритмы и структуры данных»

🔥Получите вводные занятия, ответив на 3 вопроса – https://proglib.io/w/c2161ff4

На вводной части вас ждут:

1. Лекция «Производительность алгоритмов» от руководителя разработки Яндекс.Самокатов

2. Лекция «Итеративные сортировки и линейные сортировки» от аспирант департамента искусственного интеллекта ВШЭ

3. Практические задания после лекций

4. Ссылки на дополнительные материалы для самостоятельного изучения

⚡️Переходите и начинайте учиться уже сегодня – https://proglib.io/w/c2161ff4
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
💬 Поддерживается ли в Go арифметика указателей как C++ или других языках?

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

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

Для выполнения операций, аналогичных арифметике указателей, в Go можно использовать слайсы, которые обеспечивают безопасный доступ к элементам массива и автоматически управляют размером и ёмкостью.
🔥1
💬 Когда pointer ресивер предпочтительнее использовать, чем value ресивер в Go?

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

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

В примере ниже, оба метода Scale и Abs имеют тип ресивера *Vertex, хотя метод Abs не должен изменять свой ресивер.


package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}


В общем случае, все методы для данного типа должны использовать либо только pointer ресивер, либо только value ресивер, чтобы избежать путаницы и обеспечить согласованность.
👍31
⚡️Proglib запускает канал про ИИ для генерации звука

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

⭐️генерация голоса и музыки
⭐️замена и перевод речи
⭐️распознавание звуков

👉Подписывайтесь!
💬 Интерфейс и any (interface{}) в Go — это одно и то же? Объясните простыми словами.

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

any — это псевдоним для пустого интерфейса interface{}. Пустой интерфейс interface{} может содержать значение любого типа, поскольку он не требует реализации никаких методов.
🥱5👍3
💬 Почему crypto/rand в некоторых кейсах предпочтительнее использовать вместо math/rand для генерации ключей в Go?

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

Пакет math/rand отлично подходит для генерации псевдослучайных чисел. Но у этого метода есть серьезный недостаток: если кто-то узнает, как генерируются числа (начальное значение seed), он сможет предсказать будущие числа.


import "math/rand"

func Key() string {
// rand.Seed(time.Now().UnixNano()) // deprecated
r := rand.New(rand.NewSource(time.Now().UnixNano()))

buf := make([]byte, 16)

for i := range buf {
buf[i] = byte(r.Intn(256))
}

return fmt.Sprintf("%x", buf)
}


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

С другой стороны, crypto/rand предлагает лучшее решение для генерации чисел, которые криптографически безопасны. Эта библиотека разработана для полной непредсказуемости, используя источники случайности, предоставляемые ОС, которые обычно гораздо сложнее предсказать.


import "crypto/rand"

func Key() string {
buf := make([]byte, 16)

_, err := rand.Read(buf)
if err != nil {
panic(err)
}

return fmt.Sprintf("%x", buf)
}


Использование crypto/rand особенно необходимо для операций, таких как шифрование, аутентификация или любой другой контекст, где безопасность имеет критическое значение.

Опять же, если мы генерируем ключи для целей, не связанных с безопасностью, math/rand вполне подойдет.
👍114
💬 Когда процесс в Linux может не реагировать на SIGKILL?

🔸 Когда процесс является зомби-процессом, который уже завершился, но не освободил свои ресурсы. Зомби не может принимать сигналы и ожидает, что его родительский процесс считает его статус с помощью системного вызова wait.
🔸 Когда процесс находится в состоянии блокировки. Он выполняет неотменяемый системный вызов, такой как ожидание ввода-вывода или другого события, которое не наступило. Процесс не может завершиться, пока операционная система не вернет его в нормальное состояние.
🔸 Когда процесс является процессом init. Он не получает от ОС сигналов, которые не хочет обрабатывать. Процесс init может игнорировать SIGKILL, так как он является особым процессом, который отвечает за запуск и завершение других процессов.
👍13❤‍🔥2
📖 ТОП-10 книг о том, как правильно построить карьеру в IT

Хотите преуспеть в IT? Ознакомьтесь с нашим списком лучших книг, которые помогут вам выстроить успешную карьеру в этой динамичной отрасли!

Читать статью, чтобы ознакомиться со всеми книгами 👉 https://proglib.io/sh/glq68BCSKj
👍1