В Go пустой интерфейс
interface{}
является особым типом, который может содержать значение любого типа. Это связано с тем, что в Go любой тип реализует пустой интерфейс, поскольку в нем нет методов, которые нужно реализовать. Поскольку пустой интерфейс не требует реализации каких-либо методов, любой тип в Go автоматически реализует этот интерфейс. Это делает пустой интерфейс универсальным контейнером для значений любых типов.
type interface{} interface {}
Типа конкретного значения
Самого значения
Когда значение присваивается переменной типа интерфейс, Go сохраняет информацию о типе и значении этого значения. Для пустого интерфейса эта информация может быть любого типа.
Когда значение из пустого интерфейса приводится к конкретному типу, происходит проверка типа во время выполнения. Если значение внутри интерфейса действительно является указанным типом, приведение успешно. В противном случае приведение не удается, и возвращается значение
nil
или происходит паника, если приведение выполнено без проверки.Присваивание значений пустому интерфейсу
package main
import "fmt"
func main() {
var i interface{}
i = 42
fmt.Println(i) // 42
i = "hello"
fmt.Println(i) // hello
}
Утверждение типа (Type Assertion)
package main
import "fmt"
func main() {
var i interface{} = "hello"
// Утверждение типа с проверкой
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
} else {
fmt.Println("Not a string")
}
// Утверждение типа без проверки
// Это вызовет панику, если тип не соответствует
s = i.(string)
fmt.Println("String:", s)
}
Использование 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")
printType(42)
printType(true)
printType(3.14)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Используйте runtime.ReadMemStats для получения данных о памяти или pprof для профилирования, чтобы выявить функции с высоким потреблением ресурсов. Профили можно анализировать через CLI или визуализировать.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
Go — это императивный язык программирования.
Императивное программирование означает, что программист явно указывает шаги, которые необходимо выполнить для достижения результата. Код в Go представляет собой последовательность команд, изменяющих состояние программы.
package main
import "fmt"
func main() {
sum := 0
for i := 1; i <= 5; i++ {
sum += i // Явно изменяем переменную sum
}
fmt.Println("Сумма:", sum)
}
Хотя Go — это в первую очередь императивный язык, в нем есть элементы декларативного подхода. Например:
map
, filter
через срезы и функции высшего порядка. интерфейсы позволяют писать код, в котором детали реализации скрыты (инкапсуляция).
вместо явного управления потоками, мы декларируем взаимодействие через каналы.
package main
import "fmt"
func mapSlice(slice []int, f func(int) int) []int {
result := make([]int, len(slice))
for i, v := range slice {
result[i] = f(v) // Декларативное применение функции к элементам
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5}
squared := mapSlice(nums, func(n int) int { return n * n })
fmt.Println(squared) // [1 4 9 16 25]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Составной индекс (Composite Index) — это индекс, который создаётся сразу на нескольких колонках таблицы базы данных. Он помогает ускорить поиск и сортировку данных, особенно если запросы используют условия по нескольким полям.
Если часто выполняются запросы с фильтрацией по нескольким колонкам (
WHERE col1 = X AND col2 = Y
), составной индекс ускоряет их выполнение.Если запросы используют
ORDER BY col1, col2
, индекс помогает избежать дополнительной сортировки.Без индекса СУБД вынуждена выполнять полный перебор (Full Table Scan), что занимает больше времени.
Он строится по нескольким колонкам и фактически представляет собой отсортированную структуру данных. Например, в PostgreSQL или MySQL создаётся так:
CREATE INDEX idx_name ON users (last_name, first_name);
Теперь база данных будет использовать индекс для запросов:
SELECT * FROM users WHERE last_name = 'Иванов' AND first_name = 'Петр';
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
1. Избегайте длительной блокировки: Держите мьютекс заблокированным только на время выполнения критической секции.
2. Всегда разблокируйте мьютекс: Используйте defer для автоматического вызова Unlock.
3. Не вызывать блокировки в неправильном порядке: Избегайте взаимной блокировки (deadlock).
4. Используйте минимальное количество мьютексов: Чем больше мьютексов, тем выше вероятность ошибок.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Планировщик задач (Scheduler) управляет выполнением процессов и горутин (в случае Go). В контексте операционных систем и языков программирования, таких как Golang, планировщик отвечает за распределение вычислительных ресурсов.
Это легковесный поток, который выполняет код. В отличие от ОС-потоков, она не требует большого количества памяти и управляется рантаймом Go.
Включает стек, контекст выполнения, а также статус (ждёт, выполняется, завершена).
Переключается между потоками ОС прозрачно для разработчика.
Можно создать десятки тысяч горутин без значительных затрат памяти.
go func() {
fmt.Println("Привет из горутины!")
}()
M (Machine) представляет собой реальный поток ОС (kernel thread), на котором выполняются горутины.
Соответствует потокам ОС (
pthread
в Linux, Windows Thread
в Windows). Может одновременно выполнять только одну горутину.
Количество
M
зависит от GOMAXPROCS
, но обычно Go создаёт столько потоков, сколько ядер в системе. runtime.GOMAXPROCS(4) // Использовать 4 ядра процессора
Это сущность, которая отвечает за распределение горутин (
G
) между потоками (M
). P
управляет очередью горутин и раздаёт их потокам (M
). По умолчанию количество
P
равно количеству GOMAXPROCS
. Горутину нельзя выполнить без доступного
P
. [Processor P1] ----> [Machine M1] ----> Выполняет горутины G1, G2
[Processor P2] ----> [Machine M2] ----> Выполняет горутины G3, G4
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Select с default позволяет немедленно выполнять код, если нет доступных каналов. Это полезно для обработки задач без блокировки:
- Выполняет действие, если нет данных для чтения/записи.
- Используется для таймаутов, проверки состояния или фоновых операций.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Карты (maps) предоставляют несколько основных функций и операций для работы с ними. Эти функции позволяют добавлять, удалять, получать значения и проверять наличие ключей в карте.
Для этого используется ключевое слово
map
, после которого указываются типы ключей и значений.var myMap map[string]int
Это можно сделать с помощью функции
make
или литерала карты.// Инициализация с помощью make
myMap = make(map[string]int)
// Инициализация с помощью литерала карты
myMap = map[string]int{
"Alice": 25,
"Bob": 30,
}
Для этого используется синтаксис индексирования.
myMap["Charlie"] = 35
myMap["Alice"] = 26 // обновление значения по ключу "Alice"
Для этого используется синтаксис индексирования.
age := myMap["Alice"]
fmt.Println(age) // 26
Чтобы проверить это можно использовать двойное присваивание.
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}
Для этого используется встроенная функция
delete
.delete(myMap, "Bob")
Для этого используется цикл
for range
.for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
Пример
package main
import (
"fmt"
)
func main() {
// Инициализация карты с помощью литерала
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
// Добавление нового элемента
myMap["Charlie"] = 35
// Обновление существующего элемента
myMap["Alice"] = 26
// Извлечение значения по ключу
age := myMap["Alice"]
fmt.Println("Age of Alice:", age) // 26
// Проверка существования ключа
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}
// Удаление элемента
delete(myMap, "Bob")
// Итерация по карте
for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
1. Добавляет счетчик с количеством ожидаемых горутин.
2. Горутины уменьшают счетчик вызовом Done() после завершения.
3. Ожидание завершения всех горутин выполняется через Wait().
Используется для управления параллельными задачами и предотвращения преждевременного завершения программы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Grafana — это инструмент для визуализации и мониторинга данных. Он позволяет строить дашборды (панели) с графиками, метриками и алертами, получая данные из различных источников (Prometheus, InfluxDB, Loki, MySQL и других).
создание графиков, таблиц, гистограмм и других визуальных представлений.
отслеживание метрик серверов, баз данных, контейнеров и микросервисов.
поддерживает Prometheus, Elasticsearch, MySQL, PostgreSQL и десятки других.
оповещения (email, Slack, Telegram) при достижении критических значений.
удобный интерфейс для анализа производительности систем.
Можно отслеживать загрузку CPU, RAM, количество запросов в базе, ошибки и задержки API.
Позволяет наблюдать за работой Kubernetes, Docker, CI/CD-пайплайнов и микросервисов.
Может использоваться для отображения KPI, продаж, конверсий и других данных.
Если сервер падает или нагрузка превышает порог – Grafana уведомит команду.
Устанавливаем Prometheus и Grafana
Добавляем Prometheus как источник данных в Grafana
Создаём дашборд с метриками, например
Количество HTTP-запросов
Время ответа сервера
Количество активных соединений
http_requests_total{job="web_service"}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Это потокобезопасная структура данных для одновременного доступа из нескольких горутин:
1. Не требует мьютексов для чтения/записи.
2. Оптимизирован для сценариев с частым чтением и редкой записью.
3. Поддерживает методы Load, Store, Delete, Range.
Подходит для кэшей и других сценариев, где производительность важнее.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Это процесс копирования и поддержания данных в синхронном или асинхронном порядке между несколькими базами данных или серверами. Это позволяет данным быть доступными на различных серверах, что увеличивает доступность, устойчивость к сбоям и может улучшить производительность приложений за счёт распределения нагрузки на разные серверы или узлы.
Позволяет системе продолжать работать даже при сбое одного или нескольких серверов. При наличии нескольких копий данных, система может переключиться на использование актуальной копии данных на другом сервере.
Может помочь распределить запросы чтения между несколькими узлами, тем самым уменьшая нагрузку на один сервер и улучшая время отклика в приложениях.
Реплик в разных географических локациях может улучшить время доступа к данным для пользователей, которые находятся ближе к одной из реплик.
Данных на разные физические места уменьшает риски, связанные с потерей данных в случае катастроф.
Данные одновременно записываются в основную и реплицированную базы данных. Транзакция считается завершенной только после успешной записи на всех репликах. Это обеспечивает высокую степень согласованности данных, но может снижать производительность из-за задержек, связанных с ожиданием подтверждения от всех реплик.
Изменения данных первоначально записываются на основной сервер, и только после этого асинхронно передаются на репликационные серверы. Это метод быстрее, поскольку основная система не ждёт подтверждения от реплик перед завершением транзакции. Однако это также увеличивает риск несогласованности данных между репликами.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
1. Создайте карту и мьютекс как пару.
2. Заблокируйте мьютекс перед доступом к карте, разблокируйте после.
3. Используйте sync.Map, если не хотите вручную управлять блокировками.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Карты (maps) представляют собой ассоциативные массивы, которые связывают ключи с соответствующими значениями. Работа с картами включает получение и запись значений, и Go предоставляет удобный синтаксис для этих операций. Рассмотрим особенности синтаксиса получения и записи значений в карты.
Для этого используется синтаксис индексирования
value := myMap[key]
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
value := myMap["Alice"]
fmt.Println("Alice:", value) // Alice: 25
}
Для этого используется синтаксис двойного присваивания
value, exists := myMap[key]
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
value, exists := myMap["Charlie"]
if exists {
fmt.Println("Charlie:", value)
} else {
fmt.Println("Charlie not found")
}
}
Для этого используется синтаксис индексирования:
myMap[key] = value
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{}
// Добавление значений
myMap["Alice"] = 25
myMap["Bob"] = 30
fmt.Println("Map:", myMap) // Map: map[Alice:25 Bob:30]
// Обновление значения
myMap["Alice"] = 26
fmt.Println("Updated Map:", myMap) // Updated Map: map[Alice:26 Bob:30]
}
Для этого используется встроенная функция
delete
:delete(myMap, key)
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
// Удаление значения по ключу
delete(myMap, "Alice")
fmt.Println("Map after deletion:", myMap) // Map after deletion: map[Bob:30]
}
Если ключ отсутствует в карте, при попытке получения значения будет возвращено нулевое значение типа значения карты. Например, для карты
map[string]int
это будет 0
.package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
}
value := myMap["Bob"] // Ключ "Bob" отсутствует
fmt.Println("Value:", value) // Value: 0
}
Нельзя записывать значения в
nil
карту. Это приведет к панике времени выполнения.package main
func main() {
var myMap map[string]int // nil карта
myMap["Alice"] = 25 // Вызовет панику: runtime error: assignment to entry in nil map
}
Порядок итерации по карте не определен и может различаться между разными запусками программы.
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 35,
}
for key, value := range myMap {
fmt.Printf("%s: %d\n", key, value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
1. RWMutex (Read-Write Mutex):
- Позволяет нескольким горутинам одновременно читать данные (RLock/RUnlock).
- Запись (Lock/Unlock) блокирует всех, включая читателей.
2. Обычный Mutex:
- Полностью блокирует доступ, независимо от операции (чтение или запись).
RWMutex эффективнее для операций с преобладанием чтения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Forwarded from easyoffer
Привет, ребята!
1,5 года я учился на программиста, а сайт easyoffer.ru стал моим пет-проектом. Я создавал его, потому что:
а) нужно было добавить хоть какой-нибудь проект в резюме
б) подготовиться к прохождению собесов
И всё получилось! Благодаря еasyoffer я успешно прошёл собеседование и устроился Python Junior-разработчиком на удаленку с зарплатой 115 тысяч рублей.
Однако ещё во время разработки я понял, что у этого проекта есть потенциал. Казалось, что сайт может стать популярным и, возможно, превратиться в стартап.
По-этому я с самого начала заложил в проект минимальную бизнес-модель, на случай, если сайт начнёт набирать трафик. Я предложил пользователям полный доступ к сайту в обмен на подписку на Telegram-каналы. Это позволяло развивать аудиторию, а в будущем — зарабатывать на рекламе.
Результат превзошёл ожидания!
С момента запуска easyoffer посетило 400 тысяч человек. А когда доход с рекламы превысил мою зарплату программиста, я принял решение уйти с работы и полностью посвятить себя разработке новой версии сайта.
Вот так, зайдя в IT, через 4 месяца вышел через свой же пет-проект. Мне очень повезло
Уже год я работаю над easyoffer 2.0.
Это будет более масштабный и качественной новый проект:
– Появится тренажер
– Появятся задачи из собесов
– Фильтрация контента по грейдам
и еще очень много фич, о которых я расскажу позже.
Хочу, довести easyoffer до ума, чтобы сайт стал настоящим помощником для всех, кто готовится к собеседованиям.
По этому в ближайшее время я объявлю о старте краудфандинговой кампании, чтобы ускорить разработку и я готов щедро отблагодарить всех, кто поддержит проект.
А те, кто поддержат проект первыми, получат специальные лимитированные выгодные вознаграждения. Следите за этим телеграм каналом, если хотите стать первыми сапортерами.
1,5 года я учился на программиста, а сайт easyoffer.ru стал моим пет-проектом. Я создавал его, потому что:
а) нужно было добавить хоть какой-нибудь проект в резюме
б) подготовиться к прохождению собесов
И всё получилось! Благодаря еasyoffer я успешно прошёл собеседование и устроился Python Junior-разработчиком на удаленку с зарплатой 115 тысяч рублей.
Однако ещё во время разработки я понял, что у этого проекта есть потенциал. Казалось, что сайт может стать популярным и, возможно, превратиться в стартап.
По-этому я с самого начала заложил в проект минимальную бизнес-модель, на случай, если сайт начнёт набирать трафик. Я предложил пользователям полный доступ к сайту в обмен на подписку на Telegram-каналы. Это позволяло развивать аудиторию, а в будущем — зарабатывать на рекламе.
Результат превзошёл ожидания!
С момента запуска easyoffer посетило 400 тысяч человек. А когда доход с рекламы превысил мою зарплату программиста, я принял решение уйти с работы и полностью посвятить себя разработке новой версии сайта.
Вот так, зайдя в IT, через 4 месяца вышел через свой же пет-проект. Мне очень повезло
Уже год я работаю над easyoffer 2.0.
Это будет более масштабный и качественной новый проект:
– Появится тренажер
– Появятся задачи из собесов
– Фильтрация контента по грейдам
и еще очень много фич, о которых я расскажу позже.
Хочу, довести easyoffer до ума, чтобы сайт стал настоящим помощником для всех, кто готовится к собеседованиям.
По этому в ближайшее время я объявлю о старте краудфандинговой кампании, чтобы ускорить разработку и я готов щедро отблагодарить всех, кто поддержит проект.
А те, кто поддержат проект первыми, получат специальные лимитированные выгодные вознаграждения. Следите за этим телеграм каналом, если хотите стать первыми сапортерами.
👍1
Это предопределенное идентификатор, используемое для создания последовательностей целочисленных констант. Он применяется в контексте объявления констант и автоматически инкрементируется на единицу с каждым новым значением. Обычно используется для определения множества связанных констант без необходимости вручную назначать каждому элементу значение.
Начинает счет с 0 в каждой новой группе констант.
Каждое последующее использование
iota
в одной группе констант увеличивает его значение на 1.При каждом новом объявлении константного блока
iota
сбрасывается до 0.package main
import "fmt"
const (
A = iota // 0
B // 1
C // 2
)
func main() {
fmt.Println(A) // Вывод: 0
fmt.Println(B) // Вывод: 1
fmt.Println(C) // Вывод: 2
}
Использование его для создания битовых флагов
package main
import "fmt"
const (
Flag1 = 1 << iota // 1 << 0 = 1
Flag2 // 1 << 1 = 2
Flag3 // 1 << 2 = 4
Flag4 // 1 << 3 = 8
)
func main() {
fmt.Println(Flag1) // Вывод: 1
fmt.Println(Flag2) // Вывод: 2
fmt.Println(Flag3) // Вывод: 4
fmt.Println(Flag4) // Вывод: 8
}
Сброс его в новом блоке
package main
import "fmt"
const (
X = iota // 0
Y // 1
)
const (
Z = iota // 0 (новый блок констант, iota сбрасывается)
W // 1
)
func main() {
fmt.Println(X) // Вывод: 0
fmt.Println(Y) // Вывод: 1
fmt.Println(Z) // Вывод: 0
fmt.Println(W) // Вывод: 1
}
Можно использовать в выражениях и совместно с другими константами для создания более сложных последовательностей.
package main
import "fmt"
const (
_ = iota // пропускаем 0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
)
func main() {
fmt.Println("KB:", KB) // Вывод: KB: 1024
fmt.Println("MB:", MB) // Вывод: MB: 1048576
fmt.Println("GB:", GB) // Вывод: GB: 1073741824
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Голодание (starvation) — ситуация, когда горутина или процесс не получают доступа к ресурсу из-за приоритета других задач. Причины:
1. Неправильное управление приоритетами.
2. Частое использование долгих блокировок (например, приоритетная блокировка RWMutex для записи).
Результат: одни задачи постоянно выполняются, другие блокируются бесконечно.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Это версии протокола HTTP, каждая из которых имеет свои особенности и улучшения по сравнению с предыдущими версиями. Важные различия между этими версиями включают следующие аспекты:
Поддерживает одновременное открытие нескольких TCP соединений (обычно 6-8), что позволяет загружать несколько ресурсов параллельно. Однако каждое соединение может обрабатывать только один запрос за раз, что приводит к задержкам из-за блокировки очереди (head-of-line blocking).
Вводит мультиплексирование, позволяющее отправлять множество запросов и ответов асинхронно через одно единственное TCP соединение. Это значительно уменьшает задержки и улучшает производительность при загрузке страниц с большим количеством ресурсов.
Является текстовым протоколом, что означает, что запросы и ответы форматируются в виде читаемого текста.
Бинарный протокол, который делает передачу данных более эффективной и менее подверженной ошибкам в синтаксическом анализе. Бинарный формат упрощает реализацию парсеров и уменьшает размер передаваемых данных.
Заголовки передаются без сжатия, что может привести к значительному объему передаваемых данных, особенно если одни и те же заголовки отправляются повторно с каждым запросом.
Использует механизм сжатия заголовков HPACK, который уменьшает избыточность заголовков, сжимая их перед отправкой. Это особенно эффективно для повторяющихся запросов к одним и тем же серверам.
Не поддерживает приоритизацию запросов, из-за чего браузеры должны использовать эвристики для управления приоритетами ресурсов.
Поддерживает явную приоритизацию запросов, позволяя клиенту указывать приоритет обработки ресурсов, что делает загрузку страниц более эффективной.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2