Контексты (context.Context) представляют собой интерфейс, который используется для передачи мета-данных, управления сроками действия и отменой операций в иерархии вызовов функций. Основная цель контекста — обеспечение способа для остановки выполнения программы (например, запросов или подпроцессов) по требованию. Это особенно полезно в сетевых приложениях, где вам может потребоваться прервать выполнение операции, которая больше не требуется или занимает слишком много времени.
Контекст предназначен для безопасной передачи по горутинам, что означает, что он может быть передан между различными частями вашей программы, выполняющимися в разных горутинах.
Контекст может быть отменен, что автоматически сигнализирует всем получателям этого контекста о необходимости остановить свою работу. Это обеспечивается через канал, который закрывается, когда контекст отменяется.
Контекст может иметь установленный таймаут или дедлайн, после достижения которого он автоматически отменяется.
Контексты могут нести значения — пары ключ-значение, которые можно устанавливать и получать. Эти значения обычно используются для передачи данных, специфичных для запроса, таких как идентификаторы сессий или токены авторизации.
🟠context.Background()
Возвращает пустой контекст, который никогда не отменяется. Обычно используется в основной функции и при инициализации.
context.TODO()
Используется для указания, что должен быть предоставлен подходящий контекст. Обычно применяется в разработке и при рефакторинге.
context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)
Создает новый контекст с возможностью отмены.
context.WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
Создает контекст, который автоматически отменяется в указанный
deadline
.context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
Аналогичен
WithDeadline
, но устанавливает время жизни контекста на основе заданного таймаута.func operation1(ctx context.Context) {
select {
case <-time.After(5 * time.Second):
fmt.Println("operation1 completed")
case <-ctx.Done():
fmt.Println("operation1 cancelled")
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go operation1(ctx)
// Дожидаемся завершения или отмены операции
<-ctx.Done()
if err := ctx.Err(); err != nil {
fmt.Println("main:", err)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
PostgreSQL поддерживает:
- B-Tree — по умолчанию, для равенства и диапазонов.
- Hash — для быстрого поиска по точному совпадению.
- GIN (Generalized Inverted Index) — для массивов, JSONB, полнотекстового поиска.
- GiST (Generalized Search Tree) — для гео-данных и поиска по диапазону.
- BRIN (Block Range Index) — для очень больших таблиц с логически отсортированными данными.
- Expression indexes — индексы по вычислениям, а не просто по полю.
- Partial indexes — индексы по части строк (например, только по активным записям).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Go runtime — это встроенная среда выполнения, которая управляет памятью, потоками, сборкой мусора и планировщиком горутин. Он делает Go удобным для многопоточного и высоконагруженного программирования без необходимости вручную управлять потоками.
Горутины (goroutines) — лёгкие потоки, управляемые Go.
Планировщик (scheduler) — распределяет горутины по потокам ОС.
Модель памяти — управление стеком и кучей.
Сборщик мусора (GC) — автоматически очищает неиспользуемую память.
Syscalls — взаимодействие с ОС.
Горутины легче, чем потоки ОС: Go может запускать миллионы горутин, а планировщик (M:N) распределяет их по потокам ОС.
Go использует M:N-модель, где:
-
M
— системные потоки (OS threads). -
N
— горутины (goroutines). -
P
— процессоры (logical processors) — управляют выполнением горутин. P
привязан к M
, а G
(горутины) распределяются между `P` динамически. Это позволяет Go эффективно использовать CPU без ручного управления потоками.
Goroutine (G1, G2, G3, ...)
↓
Scheduler → P (Processor) → M (OS Thread) → CPU
Стек (stack) в Go динамический — он начинается с 2 KB и увеличивается при необходимости.
Если стек заполнен, Go автоматически расширяет его.
В отличие от C, Go не требует
malloc/free
, так как есть GC (garbage collector). Go использует автоматический сборщик мусора, который:
Работает параллельно с программой
Минимизирует паузы (low-latency GC)
Очищает неиспользуемые объекты из кучи
import "runtime"
runtime.GC() // Принудительный запуск сборщика мусора (обычно не нужно)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4💊1
Линтеры повышают качество кода, находя ошибки еще на этапе разработки. Это помогает избежать ошибок в продакшене.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
ACID — это набор свойств транзакций в базах данных, обеспечивающий надежность и целостность данных.
Транзакция выполняется либо полностью, либо не выполняется вовсе.
Пример: Если при переводе денег со счета A на счет B ошибка произошла на полпути, изменения откатываются.
Данные остаются в правильном состоянии до и после транзакции.
Пример: Если сумма на всех счетах банка должна оставаться неизменной, транзакция не должна нарушить это правило.
Одновременные транзакции не мешают друг другу.
Пример: Два клиента покупают один и тот же товар, но база данных правильно обрабатывает, кто купил первым.
После завершения транзакции изменения сохраняются, даже если система сломается.
Пример: Если заказ оформлен, он не исчезнет при внезапном отключении электричества.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Захват переменной — это процесс, при котором замыкание получает доступ к переменной, объявленной вне его тела.
Захваченная переменная продолжает жить в памяти, пока замыкание живо, даже если её внешняя область уже вышла из стека.
В Go это может вызывать неожиданные эффекты при захвате переменной цикла, если не делать копию значения внутри тела цикла.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3👍2
Оптимизация кода в Go может быть выполнена на нескольких уровнях:
Использование более эффективных алгоритмов (например,
O(log n)
вместо O(n^2)
). Выбор подходящих структур данных (например, map
вместо срезов для поиска по ключу). Снижение количества аллокаций (использование
sync.Pool
, предварительное выделение памяти). Использование []byte
вместо string
, если требуется частое изменение строки. Минимизация копирования данных, например, передача []byte
по ссылке вместо копирования. Использование
worker pool
, чтобы избежать избыточного создания горутин. Ограничение количества параллельных задач (runtime.GOMAXPROCS
). Использование каналов правильной ёмкости для минимизации блокировок. Буферизация (
bufio.Reader
, bufio.Writer
). Использование асинхронных операций при работе с файлами или сетью. Использование io.Pipe()
для потоковой обработки данных. pprof
для анализа CPU, памяти и блокировок. race detector
(-race
флаг) для выявления проблем с конкурентным доступом. Инструменты трассировки (trace
). Пример неэффективного кода
func inefficient() []string {
var result []string
for i := 0; i < 1000; i++ {
result = append(result, fmt.Sprintf("Item %d", i)) // Частые аллокации
}
return result
}
Оптимизированный вариант
func efficient() []string {
result := make([]string, 0, 1000) // Выделяем память заранее
for i := 0; i < 1000; i++ {
result = append(result, fmt.Sprintf("Item %d", i))
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
В Go методы создаются для структур (или типов) внутри пакета. Это позволяет добавлять логику и поведение объектам.
Допустим, мы создаем пакет
mathutils
, который будет содержать метод для структуры Calculator
.package mathutils
// Calculator - структура с данными
type Calculator struct {
A, B int
}
// Sum - метод для сложения чисел A и B
func (c Calculator) Sum() int {
return c.A + c.B
}
Теперь мы можем использовать этот метод в основном файле программы.
package main
import (
"fmt"
"mypackage/mathutils" // Импортируем наш пакет
)
func main() {
calc := mathutils.Calculator{A: 5, B: 3}
fmt.Println("Sum:", calc.Sum()) // Выведет: Sum: 8
}
Методы можно объявлять как для значений (
func (c Calculator)
) так и для указателей (func (c *Calculator)
). Когда использовать указатели?
Если метод изменяет данные структуры.
Чтобы избежать копирования больших структур.
func (c *Calculator) Multiply(factor int) {
c.A *= factor
c.B *= factor
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Основные типы соединений в SQL:
- INNER JOIN — только совпадающие записи.
- LEFT JOIN — все из левой таблицы, даже без пары.
- RIGHT JOIN — все из правой таблицы.
- FULL OUTER JOIN — всё из обеих таблиц, где возможно — объединяется.
- CROSS JOIN — декартово произведение.
- SELF JOIN — соединение таблицы с самой собой.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Планировщик задач (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
💊3
map
? Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Триггер — это специальная процедура в СУБД, которая автоматически выполняется при определённом событии (например,
INSERT
, UPDATE
, DELETE
) в таблице.Когда выполняется определённое действие с таблицей, триггер срабатывает автоматически и выполняет заданную логику. Это полезно для:
- Автоматической проверки данных.
- Поддержания целостности информации.
- Логирования изменений.
Допустим, у нас есть таблица
orders
, и мы хотим автоматически сохранять историю изменений заказов в таблицу orders_log
.CREATE TABLE orders_log (
id SERIAL PRIMARY KEY,
order_id INT,
old_status TEXT,
new_status TEXT,
changed_at TIMESTAMP DEFAULT now()
);
CREATE OR REPLACE FUNCTION log_order_update()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO orders_log (order_id, old_status, new_status)
VALUES (OLD.id, OLD.status, NEW.status);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER order_status_change
AFTER UPDATE ON orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION log_order_update();
Используется для проверки или модификации данных перед изменением.
Чаще всего используется для логирования или дополнительных действий.
Позволяет заменить выполнение операции (
INSERT
, UPDATE
, DELETE
).Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В Go каналы (
chan
) можно закрывать с помощью close(channel)
, чтобы показать, что больше не будет отправляться данных. Как закрыть канал?
ch := make(chan int)
close(ch) // Закрываем канал
Полный пример
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 3; i++ {
ch <- i // Отправляем данные
}
close(ch) // Закрываем канал
}()
for val := range ch { // Читаем пока канал не закроется
fmt.Println(val)
}
fmt.Println("Канал закрыт, чтение завершено")
}
Выход
1
2
3
Канал закрыт, чтение завершено
Используем
val, ok := <-ch
: -
ok == true
→ канал открыт, есть данные. -
ok == false
→ канал закрыт. package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
val, ok := <-ch
fmt.Println("val:", val, "ok:", ok) // val: 0 ok: false
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
В Go механизм сборки мусора называется Garbage Collector (GC).
Go использует автоматический сборщик мусора с конкурентной, трицветной, инкрементальной стратегией.
выполняется параллельно с работой программы.
объекты помечаются как белые, серые и чёрные.
работает порциями, а не останавливает программу надолго.
мусор, который будет удалён.
те, которые находятся в обработке.
используемые объекты, которые не подлежат удалению.
Чтобы уменьшить нагрузку на GC:
Используйте пул объектов (
sync.Pool
). Минимизируйте аллокации в куче (например, используйте
[]byte
вместо string
, если можно). Ограничивайте долгоживущие объекты, так как они реже сканируются.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
HAVING
— это оператор в SQL, который фильтрует группированные (GROUP BY
) данные по агрегатным функциям (SUM
, COUNT
, AVG
, MAX
, MIN
). WHERE
фильтрует отдельные строки до группировки. HAVING
фильтрует группы строк после GROUP BY
. Теперь посчитаем сумму продаж по категориям и оставим только те, где сумма > 250
SELECT category, SUM(amount) AS total_sales
FROM sales
GROUP BY category
HAVING SUM(amount) > 250;
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Тип string в Go — это последовательность байтов, закодированных в UTF-8.
Он реализован как структура:
- указатель на массив байтов;
- длина строки.
Строки неизменяемы. Любая операция, которая кажется «изменением», на самом деле создаёт новую строку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2