Golang | Вопросы собесов
4.33K subscribers
27 photos
694 links
Download Telegram
🤔 Какие бывают версии HTTP, используемые?

Поддерживает HTTP/1.0, HTTP/1.1, HTTP/2 и HTTP/3. Использование HTTP/2 встроено в стандартную библиотеку, а поддержка HTTP/3 возможна через сторонние библиотеки.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что может быть пустым интерфейсом?

Пустой интерфейс interface{} является универсальным контейнером, который может содержать значение любого типа. Это связано с тем, что в Go любой тип автоматически реализует пустой интерфейс, поскольку в нем нет методов, которые нужно реализовать.

🟠Примитивные типы
числа, строки, булевы значения и т.д.
🟠Композитные типы
массивы, срезы, карты, структуры.
🟠Функции
функции различных типов.
🟠Другие интерфейсы
значения, которые реализуют другие интерфейсы.

🚩Примеры

Примитивные типы
package main

import "fmt"

func main() {
var i interface{}
i = 42
fmt.Println(i) // Output: 42

i = "hello"
fmt.Println(i) // Output: hello

i = true
fmt.Println(i) // Output: true
}


Композитные типы
package main

import "fmt"

func main() {
var i interface{}

i = []int{1, 2, 3}
fmt.Println(i) // Output: [1 2 3]

i = map[string]int{"one": 1, "two": 2}
fmt.Println(i) // Output: map[one:1 two:2]

type Person struct {
Name string
Age int
}

i = Person{Name: "Alice", Age: 30}
fmt.Println(i) // Output: {Alice 30}
}


Функции
package main

import "fmt"

func main() {
var i interface{}

i = func() {
fmt.Println("Hello from function")
}

if f, ok := i.(func()); ok {
f() // Output: Hello from function
}
}


Другие интерфейсы
package main

import "fmt"

type Stringer interface {
String() string
}

type Person struct {
Name string
Age int
}

func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
var i interface{}

i = Person{Name: "Alice", Age: 30}

if str, ok := i.(Stringer); ok {
fmt.Println(str.String()) // Output: Alice (30 years old)
}
}


🚩Проверка и приведение типа

Утверждение типа
package main

import "fmt"

func main() {
var i interface{} = 42

if v, ok := i.(int); ok {
fmt.Println("Integer:", v) // Output: Integer: 42
} else {
fmt.Println("Not an integer")
}
}


Использование switch для проверки типа
package main

import "fmt"

func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}

func main() {
printType("hello") // Output: String: hello
printType(42) // Output: Integer: 42
printType(true) // Output: Boolean: true
printType(3.14) // Output: Unknown type: float64
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как защититься от ошибки во время конкурентной записи в map?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как устроена объектоориентированная модель?

Объектно-ориентированная модель отличается от традиционных ООП-языков, таких как C# или Java. Нет классов и наследования в привычном понимании. Вместо этого используются структуры (structs) и интерфейсы для реализации основных принципов ООП: инкапсуляции, композиции и полиморфизма.

🚩Концепции

🟠Структуры (Structs)
Служат аналогом классов. Они позволяют объединять данные в логически связанные группы.
type Person struct {
Name string
Age int
}


🟠Методы
Могут быть определены для структур, что позволяет связывать функции с типами.
func (p Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}


🟠Инкапсуляция
Достигается через модификаторы доступа на уровне пакета. Поля и методы, начинающиеся с заглавной буквы, экспортируемые (public), остальные — нет (private).
type Person struct {
name string // неэкспортируемое поле
Age int // экспортируемое поле
}


🟠Композиция
Go не поддерживает классическое наследование. Вместо этого используется композиция для включения функциональности одного типа в другой.
type Employee struct {
Person
Position string
}


🟠Интерфейсы
Используются для определения поведения. Типы могут реализовывать интерфейсы неявно, просто предоставляя методы, указанные в интерфейсе.
type Greeter interface {
Greet()
}

func SayHello(g Greeter) {
g.Greet()
}

type Person struct {
Name string
}

func (p Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}

func main() {
p := Person{Name: "John"}
SayHello(p)
}


🟠Полиморфизм
Достигается через интерфейсы. Любой тип, который реализует интерфейс, может быть использован вместо него.
type Greeter interface {
Greet()
}

func SayHello(g Greeter) {
g.Greet()
}

type Robot struct {
ID string
}

func (r Robot) Greet() {
fmt.Printf("Greetings, I am robot %s\n", r.ID)
}

func main() {
p := Person{Name: "John"}
r := Robot{ID: "XJ-9"}

SayHello(p)
SayHello(r)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Зачем нужна конструкция defer?

`defer` в Go откладывает выполнение функции или выражения до завершения текущей функции. Это особенно полезно для гарантированного освобождения ресурсов, таких как закрытие файлов, сокетов или освобождение блокировок, даже если функция завершится с ошибкой. `defer` улучшает читаемость кода, позволяя явно указать операции очистки рядом с инициализацией ресурсов. Вложенные `defer` выполняются в порядке стека (последний добавленный — первый выполненный).

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Сравни, как реализован ООП в Go и C#?

Объектно-ориентированное программирование (ООП) в Go и C# реализовано с использованием различных подходов и парадигм, отражающих философию и дизайн каждого языка.

🚩Go

🟠Классы и объекты
Используются структуры (struct).
type Person struct {
Name string
Age int
}

func (p *Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}


🟠Наследование
Используется композиция вместо наследования.
type Employee struct {
Person
Position string
}


🟠Инкапсуляция
Модификаторы доступа на уровне пакета (экспортируемые и неэкспортируемые поля).
type Person struct {
name string // неэкспортируемое поле
Age int // экспортируемое поле
}


🟠Полиморфизм
Реализуется через интерфейсы.
type Greeter interface {
Greet()
}

type Person struct {
Name string
}

func (p *Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}


🚩C#

🟠Классы и объекты
Используются классы.
public class Person {
public string Name { get; set; }
public int Age { get; set; }

public void Greet() {
Console.WriteLine($"Hello, my name is {Name}");
}
}


🟠Наследование
Поддерживается классическое наследование.
public class Employee : Person {
public string Position { get; set; }
}


🟠Инкапсуляция
Модификаторы доступа (public, private, protected).
public class Person {
private string name;
public int Age { get; set; }
}


🟠Полиморфизм
Через виртуальные методы и интерфейсы.
public class Person {
public virtual void Greet() {
Console.WriteLine("Hello!");
}
}

public class Employee : Person {
public override void Greet() {
Console.WriteLine("Hello, I am an employee!");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое уровни изоляции транзакций?

Уровни изоляции определяют, насколько одна транзакция изолирована от других. Они влияют на читаемость данных и защищённость от конфликтов.
Стандартные уровни:
1. Read Uncommitted — минимальная изоляция, возможны "грязные" чтения.
2. Read Committed — читаются только зафиксированные данные.
3. Repeatable Read — одна и та же строка не изменяется другими транзакциями.
4. Serializable — максимальная изоляция, предотвращает все типы конфликтов, но снижает производительность.
Чем выше уровень — тем безопаснее, но медленнее.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Возможен ли JOIN со вложенными запросами?

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

🚩Как это работает?

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

🚩Пример: JOIN с подзапросом

Допустим, у нас есть две таблицы:
- orders (id, user_id, total)
- users (id, name)
Мы хотим получить всех пользователей и их заказы, но только те заказы, где сумма больше 100
SELECT u.name, sub.total
FROM users u
JOIN (
SELECT user_id, total
FROM orders
WHERE total > 100
) AS sub ON u.id = sub.user_id;


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В чем разница между императивным и декларативным?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В чем разница процесса и потока в рамках операционной системы?

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

🚩Процесс

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

🚩Поток (Thread)

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

🚩Основные различия

🟠Изоляция
Процессы изолированы друг от друга, в то время как потоки делят состояние и ресурсы внутри одного процесса.

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

🟠Создание и управление
Создание нового процесса более ресурсоемко, чем создание потока внутри существующего процесса.

🟠Взаимодействие
Взаимодействие между процессами требует использования межпроцессного взаимодействия (IPC), такого как сокеты, разделяемая память, очереди сообщений и т. д. Потоки внутри процесса могут общаться друг с другом напрямую через общую память.

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое шардинг?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Почему нельзя брать ссылку на значение, хранящееся по ключу в map?

Нельзя напрямую взять ссылку на значение, хранящееся по ключу в карте (map), из-за особенностей реализации карт и управления памятью. Рассмотрим подробнее, почему это так.

🚩Причины, почему нельзя брать ссылку на значение в карте

🟠Внутреннее устройство карты (map)
Карты реализованы на основе хеш-таблиц. Внутреннее устройство карты предполагает, что значения могут перемещаться в памяти при выполнении операций, таких как добавление или удаление элементов. Хеш-таблица может перераспределять (реорганизовывать) свои внутренние структуры для оптимизации доступа к элементам. Это может происходить, например, когда карта увеличивается в размере.

🟠Потенциальная недействительность ссылок
Если бы была возможность брать ссылки на значения, хранящиеся в карте, то при любой операции изменения карты (добавление, удаление элементов) ссылки могли бы становиться недействительными. Это привело бы к потенциально небезопасному поведению программы, так как указатель (ссылка) мог бы указывать на уже несуществующую или перемещенную область памяти.

🚩Демонстрация проблемы

Здесь попытка взять ссылку на значение из карты могла бы привести к проблемам
package main

import "fmt"

func main() {
m := map[string]int{"a": 1, "b": 2}

// Нельзя делать так:
// p := &m["a"]

// Вместо этого можно работать с копией значения
value := m["a"]
p := &value

fmt.Println("Value:", *p) // 1

// Изменение карты
m["c"] = 3

// Ссылка на значение в карте могла бы стать недействительной
// fmt.Println("Value after map change:", *p)
}


🚩Правильные способы работы со значениями карты

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

🟠Работа с копией значения
Получить значение из карты и сохранить его в переменную.
value := m["a"]   


🟠Изменение значения в карте
Если необходимо изменить значение в карте, его нужно сначала извлечь, изменить, а затем снова записать в карту.
value := m["a"]
value = value + 10
m["a"] = value


🟠Использование указателей в качестве значений
В некоторых случаях можно использовать указатели в качестве значений карты, чтобы можно было изменять значения через указатели.
   package main

import "fmt"

func main() {
m := map[string]*int{"a": new(int), "b": new(int)}
*m["a"] = 1
*m["b"] = 2

// Теперь можно брать указатели на значения
p := m["a"]
fmt.Println("Value:", *p) // 1

// Изменение значения через указатель
*p = 42
fmt.Println("Updated Value:", *m["a"]) // 42
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как строки работают в Golang внутри?

В Go строки представляют собой неизменяемые последовательности байтов, закодированных в UTF-8. Под капотом строка — это структура, которая хранит указатель на массив байтов и длину строки. Строки неизменяемы, что означает, что при любых операциях с ними создается новая строка. Это обеспечивает безопасность и позволяет легко работать с текстом, но при этом делает операции изменения относительно дорогими.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие бывают типы в Go?

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

🚩Базовые типы

🟠Числовые типы
Целые числа:
int (размер зависит от платформы):int8, int16, int32, int64 ; uint (беззнаковый, размер зависит от платформы) ; uint8 (также известен как byte), uint16, uint32, uint64
Числа с плавающей запятой:float32, float64
Комплексные числа:complex64, complex128

🟠Булевый тип
bool (значения true и false)

🟠Символьные типы
byte (аналог uint8)
rune (аналог int32, используется для представления символов Unicode)

🟠Строки
string (последовательность байт, используемая для хранения текста)

🚩Агрегированные типы

🟠Массивы
Фиксированный размер: [n]T (например, [5]int для массива из пяти целых чисел)

🟠Срезы
Переменный размер: []T (например, []int для среза целых чисел)

🟠Структуры
Набор полей: struct (например, type Person struct { Name string; Age int })

🚩Ссылочные типы

🟠Указатели
Хранит адрес переменной: *T (например, *int для указателя на целое число)

🟠Карты (map)
Хранит пары ключ-значение: map[K]V (например, map[string]int для карты, где ключи - строки, а значения - целые числа)

🟠Функции
Определяет тип функции: func(параметры) возвращаемые_типы (например, func(int) int для функции, принимающей целое число и возвращающей целое число)

🟠Интерфейсы
Определяет методы, которые должны быть реализованы: interface{} (например, type Stringer interface { String() string })

package main

import "fmt"

// Определение структуры
type Person struct {
Name string
Age int
}

// Функция, использующая интерфейс
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
// Пример использования базовых типов
var age int = 30
var name string = "Alice"
var isStudent bool = false

// Пример использования агрегированных типов
var scores [3]int = [3]int{90, 85, 88}
var people []Person = []Person{
{Name: "Bob", Age: 25},
{Name: "Charlie", Age: 35},
}

// Пример использования ссылочных типов
var p *Person = &Person{Name: "Dave", Age: 40}
var ageMap map[string]int = map[string]int{"Alice": 30, "Bob": 25}

// Вывод данных
fmt.Println("Name:", name)
fmt.Println("Age:", age)
fmt.Println("Is student:", isStudent)
fmt.Println("Scores:", scores)
fmt.Println("People:", people)
fmt.Println("Pointer to Person:", p)
fmt.Println("Age map:", ageMap)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В чём отличие UInt от Int?

- Int — знаковое целое число, может быть как положительным, так и отрицательным.
- UInt — беззнаковое целое число, только 0 и положительные значения.
UInt полезен, если ты точно знаешь, что число не может быть отрицательным (например, размер массива). Однако арифметические операции между Int и UInt требуют явного преобразования.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие преимущества есть у Go?

Go (или Golang) обладает рядом преимуществ, которые делают его популярным.

🟠Простота и лаконичность
Был разработан с упором на простоту синтаксиса и лаконичность. Это делает язык легким для изучения и чтения кода. Минимализм языка позволяет разработчикам сосредоточиться на решении задач, а не на сложностях синтаксиса.

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

🟠Параллелизм и конкурентность
Одним из ключевых преимуществ является встроенная поддержка параллелизма и конкурентности. С помощью горутин и каналов разработчики могут легко создавать многопоточные приложения.

package main

import (
"fmt"
"time"
)

func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}

func main() {
go say("world")
say("hello")
}


🟠Сильная система типов и безопасность памяти
Имеет строгую систему типов, которая помогает предотвращать ошибки на этапе компиляции. В языке отсутствуют неявные преобразования типов, что снижает вероятность ошибок. Также Go управляет памятью с помощью встроенного сборщика мусора (garbage collector), что предотвращает утечки памяти.

🟠Встроенная поддержка
Стандартных инструментов
Поставляется с богатым набором встроенных инструментов для разработки, таких как:
go fmt для автоматического форматирования кода.
go test для запуска тестов.
go build и go run для сборки и выполнения программ.
go doc для генерации документации.

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

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

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие бывают примитивы синхронизации?

Примитивы — это средства, предотвращающие конфликты между потоками:
- Mutex — взаимное исключение.
- Semaphore — ограничение количества одновременных доступов.
- Spinlock — цикл ожидания без сна.
- RWLock (чтение-запись) — позволяет множественное чтение, но только одну запись.
- Atomic операции — безопасные базовые действия без блокировок.
- Condition variables — ожидание события от другого потока.
- Channel / Queue — для безопасного обмена данными (особенно в Go).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое SLI?

Это конкретная метрика, используемая для измерения качества обслуживания сервиса. SLI показывает, насколько хорошо сервис соответствует определенным критериям, установленным в SLO (Service Level Objective).

🚩Основные компоненты

🟠Доступность (Availability)
Процент времени, в течение которого сервис доступен для пользователей. Пример: "99.9% времени в течение месяца."
🟠Производительность (Performance)
Метрики, такие как время отклика или пропускная способность. Пример: "Среднее время отклика 200 миллисекунд."
🟠Время восстановления (MTTR - Mean Time to Recovery)
Среднее время, необходимое для восстановления сервиса после сбоя. Пример: "Среднее время восстановления 1 час."
🟠Время на устранение инцидентов (MTTA - Mean Time to Acknowledge)
Среднее время на принятие мер после обнаружения проблемы. Пример: "Среднее время реакции на инцидент 30 минут."
🟠Процент ошибок (Error Rate)
Процент запросов, завершающихся ошибкой. Пример: "Процент ошибочных запросов не более 0.1%."

🚩Примеры

🟠Доступность
"Сервис был доступен 99.95% времени за последний месяц."
🟠Производительность
"Среднее время отклика сервиса за последний месяц составило 150 миллисекунд."
🟠Время восстановления (MTTR)
"Среднее время восстановления сервиса после сбоев за последний месяц составило 45 минут."
🟠Процент ошибок (Error Rate)
"Процент ошибочных запросов за последний месяц составил 0.05%."

🚩Различие между SLA, SLO и SLI

🟠SLA (Service Level Agreement)
Соглашение между поставщиком услуги и клиентом, включающее SLO и описывающее уровень обслуживания, который должен быть достигнут. SLA может включать последствия за невыполнение SLO.

🟠SLO (Service Level Objective)
Конкретные цели или метрики, которые определяют уровень обслуживания, которого должен достигнуть сервис. SLO являются частью SLA.

🟠SLI (Service Level Indicator)
Конкретные метрики, используемые для измерения фактической производительности сервиса относительно установленных SLO. SLI — это количественные показатели, которые служат основой для SLO.

🚩Важность

🟠Измерение качества услуг
SLI позволяют количественно измерять различные аспекты работы сервиса, такие как доступность и производительность.
🟠Контроль и мониторинг
SLI используются для постоянного мониторинга сервиса и обеспечения соответствия установленным SLO.
🟠Управление производительностью
SLI помогают выявлять проблемы в работе сервиса и принимать меры для их устранения.
🟠Улучшение сервиса
Анализ SLI позволяет улучшать качество обслуживания путем выявления и устранения узких мест и проблем.

🚩Пример использования

🟠Доступность
SLI: "99.9% времени сервис доступен."
SLO: "Сервис должен быть доступен не менее 99.9% времени в течение месяца."
SLA: "Если доступность падает ниже 99.9%, клиент получает компенсацию."
🟠Производительность
SLI: "Среднее время отклика 200 миллисекунд."
SLO: "Среднее время отклика не должно превышать 250 миллисекунд для 95% запросов."
SLA: "Если время отклика превышает 250 миллисекунд, клиент получает компенсацию."

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Где аллоцируется память для горутин?

Каждая горутина получает отдельный стек, который при старте весит около 2 килобайт. Он динамически увеличивается по мере необходимости (до мегабайт), а при простое — может быть сокращён.
Таким образом, память для горутины не аллоцируется в куче сразу, а используется адаптивно.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как каналы устроены в Go?

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

🚩Основы

Могут быть типизированы, что означает, что канал может передавать значения только одного определённого типа. Они могут быть объявлены и инициализированы с помощью ключевого слова chan:
ch := make(chan int) // Канал для передачи значений типа int


🚩Отправка и получение данных

Для отправки значения в канал используется оператор <-:
ch <- 10 // Отправка значения 10 в канал


Для получения значения из канала тот же оператор используется, но в другом контексте:
value := <-ch // Прочитать значение из канала и присвоить его переменной value


🚩Блокировки

Особенностью является то, что операции отправки и получения данных являются блокирующими:
Если горутина пытается отправить данные в канал, она блокируется до тех пор, пока другая горутина не прочитает эти данные.
Аналогично, если горутина пытается прочитать данные из канала, она блокируется до тех пор, пока другая горутина не отправит данные в этот канал.

🚩Буферизация

Могут быть буферизированными, что означает, что они могут хранить ограниченное количество значений без необходимости немедленного получения. Буферизированный канал инициализируется с указанием размера буфера:
ch := make(chan int, 5) // Буферизированный канал с размером буфера 5


В буферизированном канале отправка не блокируется до тех пор, пока буфер не заполнится, и получение не блокируется до тех пор, пока буфер не опустеет.

🚩Закрытие каналов

Каналы можно закрывать, если больше нет необходимости отправлять через них данные. После закрытия канала нельзя отправлять данные, но можно продолжать получать данные до тех пор, пока канал не опустеет:
close(ch)


Проверка на то, что канал закрыт и данные исчерпаны, возможна в операции чтения:
value, ok := <-ch
if !ok {
// Канал закрыт и все данные получены
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какая средняя сложность поиска по слайсу и по Map?

1. Слайс: поиск по индексу имеет сложность O(1), а поиск по значению — O(n), так как требуется линейный перебор элементов.
2. Map: средняя сложность поиска по ключу — O(1) благодаря хешированию, но в худшем случае (при коллизиях) может достигать O(n).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM