Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Слайсы являются ссылочными типами, поэтому простое присваивание одного слайса другому создаст новую ссылку на тот же подлежащий массив. Если вы хотите создать копию слайса с независимым подлежащим массивом, можно использовать встроенную функцию
copy
или методы, такие как использование append
.Создает побайтовую копию элементов из одного слайса в другой.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Создаем новый слайс той же длины, что и оригинал
copySlice := make([]int, len(original))
// Копируем элементы из оригинального слайса в новый
copy(copySlice, original)
// Изменяем элемент в копии
copySlice[0] = 100
fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}
Использование функции
inal)
Чтобы создать новый слайс с копированными элементами.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Копируем элементы из оригинального слайса в новый слайс
copySlice := append([]int(nil), original...)
// Изменяем элемент в копии
copySlice[0] = 100
fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Тестировать распределённую систему можно через симуляцию нагрузки с помощью инструментов вроде Apache JMeter или Locust, проверку устойчивости к отказам (chaos engineering), и мониторинг метрик в реальном времени.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Это технология, используемая для изменения сетевых адресов в заголовках пакетов данных, которые проходят через маршрутизатор или межсетевой экран. Она позволяет нескольким устройствам в локальной сети использовать один и тот же публичный IP-адрес для выхода в интернет.
Фиксированный сопоставление: Один внутренний IP-адрес сопоставляется с одним внешним IP-адресом. Используется, когда необходимо, чтобы устройство в локальной сети всегда было доступно под одним и тем же публичным IP-адресом. Например Веб-сервер, который должен быть доступен из интернета под фиксированным IP-адресом.
Внутренние IP-адреса сопоставляются с пулом внешних IP-адресов. Когда внутреннее устройство инициирует соединение с интернетом, ему временно присваивается один из доступных внешних IP-адресов. Например, локальная сеть с большим количеством устройств, где не требуется фиксированный внешний IP-адрес для каждого устройства.
Несколько внутренних IP-адресов могут использовать один внешний IP-адрес, но различаются по номерам портов. Каждый внутренний IP-адрес и порт сопоставляется с уникальным внешним портом. Например, Домашние или офисные сети, где множество устройств выходят в интернет через один публичный IP-адрес.
IPv4-адресов недостаточно для всех устройств, и NAT позволяет использовать один публичный IP-адрес для множества устройств.
Внутренние IP-адреса не видны извне, что усложняет потенциальным злоумышленникам попытки атак на внутренние устройства.
NAT позволяет администрировать и контролировать сетевой трафик, предоставляя возможности для управления доступом и приоритизацией трафика.
Когда устройство в локальной сети (например, компьютер с IP-адресом 192.168.1.10) инициирует соединение с устройством в интернете, NAT изменяет исходящий IP-адрес и порт на внешний IP-адрес маршрутизатора и уникальный номер порта.
Когда ответный пакет возвращается, NAT использует таблицу сопоставлений, чтобы определить, к какому внутреннему устройству направить пакет, и изменяет внешний IP-адрес и порт обратно на внутренний IP-адрес и порт.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Объектно-ориентированное программирование (ООП) в Go и C# реализовано с использованием различных подходов и парадигм, отражающих философию и дизайн каждого языка.
Используются структуры (
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)
}
Используются классы.
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
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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