Это оператор SQL, который применяется после GROUP BY и используется для фильтрации агрегированных данных (SUM, COUNT, AVG).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
Существует один основной цикл — это цикл for. н может использоваться в различных формах, выполняя функции традиционных циклов
while
, do-while
и классического for
.С тремя выражениями
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
Как
while
package main
import "fmt"
func main() {
i := 0
for i < 5 {
fmt.Println(i)
i++
}
}
Бесконечный
package main
import "fmt"
func main() {
i := 0
for {
if i >= 5 {
break
}
fmt.Println(i)
i++
}
}
С использованием range
package main
import "fmt"
func main() {
arr := []int{1, 2, 3, 4, 5}
for index, value := range arr {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
}
Итерация по массиву
arr := [5]int{10, 20, 30, 40, 50}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
Итерация по карте
m := map[string]int{"a": 1, "b": 2, "c": 3}
for key, value := range m {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
Итерация по строке
s := "hello"
for index, char := range s {
fmt.Printf("Index: %d, Char: %c\n", index, char)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Горутины и потоки (треды) в традиционном понимании операционных систем — это две различные концепции параллельного выполнения кода, каждая из которых имеет свои особенности и преимущества. Вот ключевые различия между ними.
Горутины — это легковесные "зеленые" потоки, управляемые Go runtime. Они не являются потоками операционной системы, и Go runtime отвечает за их планирование и выполнение на доступных физических потоках. Это позволяет создавать тысячи и даже миллионы горутин в рамках одного приложения с относительно небольшими затратами памяти и CPU.
Треды — это потоки выполнения, управляемые непосредственно операционной системой. Каждый тред занимает значительно больше ресурсов, чем горутина, особенно в плане памяти и времени на создание и управление. Треды более подходят для задач, требующих высокой вычислительной мощности и прямого взаимодействия с операционной системой.
Горутины потребляют гораздо меньше памяти по сравнению с тредами. Например, стек горутины начинается с нескольких килобайт, что значительно уменьшает затраты при масштабировании.
Треды требуют большего количества памяти для каждого стека, обычно начиная от нескольких сотен килобайт до мегабайтов. Это ограничивает количество потоков, которые могут быть активными одновременно без значительного увеличения затрат на ресурсы.
Горутины могут масштабироваться до большого количества параллельных задач благодаря меньшим требованиям к ресурсам и управлению со стороны runtime Go.
Треды ограничены в масштабируемости физическими ресурсами системы и более высокими затратами на управление.
Горутины имеют намного более эффективный контекст переключения, так как Go runtime оптимизирован для работы с большим количеством горутин и их переключением.
Треды терпят большие затраты времени на переключение контекста, так как операционной системе требуется больше времени для управления потоками.
package main
import (
"fmt"
"time"
)
func say(text string) {
for i := 0; i < 5; i++ {
fmt.Println(text)
time.Sleep(time.Millisecond * 500)
}
}
func main() {
go say("Hello")
say("World")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3💊1
default выполняется, если ни один из каналов в select не готов. Это предотвращает блокировку горутины, позволяя ей продолжить выполнение программы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊7👍2
Когда сервер тормозит, важно быстро найти причину. Разберём основные направления диагностики.
Сначала проверяем логи!
Системные логи (
journalctl -u myservice
, /var/log/syslog
, /var/log/messages
) Логи приложения (например,
logs/app.log
) Nginx / Apache (
/var/log/nginx/error.log
, /var/log/httpd/error.log
) Пример просмотра последних 100 строк лога:
tail -n 100 /var/log/syslog
Если используете
docker
: docker logs my_container --tail 100 -f
Проверяем, не перегружен ли сервер:
top
htop # Более удобный интерфейс
Или просто:
ps aux --sort=-%cpu | head -10 # Топ-10 процессов по CPU
ps aux --sort=-%mem | head -10 # Топ-10 процессов по памяти
Если процесс
"myapp"
жрет CPU, смотрим его нагрузку: pidstat -p $(pgrep myapp)
Проверяем сетевую активность:
netstat -tulnp # Слушающие порты
ss -tulnp # Альтернатива netstat
Пингуем сервер:
ping google.com
Проверяем скорость соединения:
wget --output-document=/dev/null http://speedtest.tele2.net/10MB.zip
Проверяем, не забит ли диск:
df -h # Свободное место
du -sh /* | sort -h # Топ занимаемых мест
Мониторинг активности диска:
iotop # Если доступен
Если сервер использует PostgreSQL / MySQL, смотрим запросы:
SHOW PROCESSLIST; # MySQL: текущие запросы
SELECT * FROM pg_stat_activity; # PostgreSQL: активные запросы
Проверяем медленные запросы (если включен
slow_query_log
): tail -n 100 /var/log/mysql/slow.log
---
Включаем pprof и анализируем:
import _ "net/http/pprof"
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
Запускаем профайлер:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3
Тип rune представляет собой alias для типа
int32
, предназначенного для хранения Unicode кодовых точек.Строки (
string
) являются последовательностями байтов, а не символов. Это означает, что один символ может занимать больше одного байта, особенно если это символ из расширенного набора Unicode.Тип используется для работы с символами, представляемыми одной кодовой точкой Unicode. Это упрощает манипуляции с символами, так как каждая
rune
— это отдельный символ, независимо от его длины в байтах.Использование типа
rune
делает код более понятным и само-документируемым. Когда в коде виден тип rune
, это сразу указывает на то, что переменная предназначена для хранения одного символа, а не целого числа.Создание и инициализация
var r rune = '世'
fmt.Println(r) // Output: 19990
Итерация по строке
s := "Привет, 世界"
for _, r := range s {
fmt.Printf("%c ", r)
}
// Output: П р и в е т , 世 界
Преобразование между
string
ито такоеs := "Go"
runes := []rune(s)
fmt.Println(runes) // Output: [71 111]
s2 := string(runes)
fmt.Println(s2) // Output: Go
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔24💊18👍1
Нарезка (slicing) — это создание нового слайса, который указывает на подмножество элементов исходного слайса. Этот процесс включает указание начального и конечного индексов для создания нового слайса. Несмотря на свою простоту, slicing имеет несколько нюансов и потенциальных подводных камней, которые важно учитывать.
Синтаксис
newSlice := originalSlice[start:end]
start
: начальный индекс (включительно).end
: конечный индекс (исключительно).Пример
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := original[1:4] // Элементы с индексами 1, 2 и 3
fmt.Println(newSlice) // [2 3 4]
}
При нарезке слайса важно, чтобы индексы
start
и end
были в пределах длины исходного слайса. Нарушение этого правила приведет к панике (runtime panic).package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Это вызовет панику: runtime error: slice bounds out of range
// newSlice := original[1:6]
// Правильное использование
newSlice := original[1:5]
fmt.Println(newSlice) // [2 3 4 5]
}
Слайсы в Go работают как ссылки на массивы. Это означает, что если вы модифицируете элементы нового слайса, то изменения отразятся и в исходном слайсе.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := original[1:4]
newSlice[0] = 20
fmt.Println("Original:", original) // [1 20 3 4 5]
fmt.Println("New Slice:", newSlice) // [20 3 4]
}
Длина нового слайса определяется как
end - start
. Емкость нового слайса определяется как cap(original) - start
.package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := original[1:4]
fmt.Println("New Slice Length:", len(newSlice)) // 3
fmt.Println("New Slice Capacity:", cap(newSlice)) // 4
}
Если нужно создать независимую копию слайса, следует использовать функцию
copy
, чтобы изменения в новом слайсе не влияли на исходный.package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := make([]int, 3)
copy(newSlice, original[1:4])
newSlice[0] = 20
fmt.Println("Original:", original) // [1 2 3 4 5]
fmt.Println("New Slice:", newSlice) // [20 3 4]
}
Полная форма нарезки позволяет явно указать емкость нового слайса:
newSlice := original[start:end:max
Это полезно, когда вы хотите контролировать емкость нового слайса.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := original[1:3:4]
fmt.Println("New Slice:", newSlice) // [2 3]
fmt.Println("New Slice Capacity:", cap(newSlice)) // 3
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
map
? Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Оператор "квадратные скобки" (
[]
) при применении к строке используется для доступа к отдельным байтам в этой строке. Строки представлены как последовательности байтов, и оператор []
позволяет получить байт по указанному индексу. package main
import (
"fmt"
)
func main() {
str := "hello"
// Получаем байт по индексу
firstByte := str[0]
// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 104
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: h
}
В этой строке кода мы получаем байт, расположенный по индексу
0
в строке str
. В данном случае это байт, соответствующий символу 'h'.firstByte := str[0]
Здесь мы выводим байт в виде целого числа. Поскольку символ 'h' имеет ASCII-код 104, вывод будет
104
.fmt.Printf("Первый байт: %d\n", firstByte)
Мы также можем вывести байт как символ, используя формат
%c
. Это отобразит символ 'h'.fmt.Printf("Первый символ: %c\n", firstByte)
Важно понимать, что строки являются последовательностями байтов, а не символов. Это означает, что доступ по индексу с помощью
[]
дает байт, а не руну (rune). Если строка содержит многобайтовые символы (например, символы Unicode), то доступ по индексу может вернуть только один из байтов, составляющих символ.package main
import (
"fmt"
)
func main() {
str := "Привет"
// Получаем байт по индексу
firstByte := str[0]
// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 208
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: � (неполный символ)
}
Для корректной работы с многобайтовыми символами (рунами) в строках используется преобразование строки в срез рун
package main
import (
"fmt"
)
func main() {
str := "Привет"
// Преобразуем строку в срез рун
runes := []rune(str)
// Получаем руну по индексу
firstRune := runes[0]
// Выводим руну и её символ
fmt.Printf("Первая руна: %d\n", firstRune) // Выводит: 1055 (код Unicode для 'П')
fmt.Printf("Первый символ: %c\n", firstRune) // Выводит: П
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Срезать можно через оператор [start:end]:
1. Новый слайс будет ссылаться на тот же массив, что и оригинал.
2. Изменение элементов в новом слайсе отразится на оригинале.
3. Если указать только start или end, будут использованы начальные или конечные значения: slice[start:] или slice[:end].
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Массивы и слайсы могут использоваться для хранения последовательности элементов одного типа. Когда вы "подставляете" переменную в массив или слайс, вы просто присваиваете значение этой переменной одному из элементов массива или слайса.
Пример с массивом
package main
import "fmt"
func main() {
// Создаем массив из 5 целых чисел
var arr [5]int
// Создаем переменную и присваиваем ей значение
x := 10
// Подставляем переменную в массив
arr[0] = x
// Выводим массив
fmt.Println(arr) // Выводит: [10 0 0 0 0]
}
Это создает массив
arr
из 5 целых чисел, все элементы которого инициализируются значением 0
.var arr [5]int
Создаем переменную
x
и присваиваем ей значение 10
.x := 10
Присваиваем значение переменной
x
первому элементу массива arr
.arr[0] = x
Выводит содержимое массива, показывая, что первый элемент массива теперь равен
10
, а остальные элементы остаются нулями.fmt.Println(arr)
Пример со слайсом
package main
import "fmt"
func main() {
// Создаем слайс из 3 целых чисел
slice := make([]int, 3)
// Создаем переменную и присваиваем ей значение
x := 20
// Подставляем переменную в слайс
slice[1] = x
// Выводим слайс
fmt.Println(slice) // Выводит: [0 20 0]
}
Это создает слайс
slice
из 3 целых чисел, все элементы которого инициализируются значением 0
.slice := make([]int, 3)
Создаем переменную
x
и присваиваем ей значение 20
.x := 20
Присваиваем значение переменной
x
второму элементу слайса slice
.slice[1] = x
Выводит содержимое слайса, показывая, что второй элемент слайса теперь равен
20
, а остальные элементы остаются нулями.fmt.Println(slice)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
В Go обычный
map
не потокобезопасен. Если несколько горутин одновременно записывают в map
, возникнет ошибка "fatal error: concurrent map writes". Решение: использовать синхронизацию через
sync.Mutex
, sync.RWMutex
или sync.Map
. Блокируем доступ на запись и чтение через
sync.Mutex
. package main
import (
"fmt"
"sync"
)
type SafeMap struct {
mu sync.Mutex
m map[string]int
}
func (s *SafeMap) Set(key string, value int) {
s.mu.Lock() // Блокируем доступ
defer s.mu.Unlock()
s.m[key] = value
}
func (s *SafeMap) Get(key string) int {
s.mu.Lock() // Блокируем на чтение
defer s.mu.Unlock()
return s.m[key]
}
func main() {
safeMap := SafeMap{m: make(map[string]int)}
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
safeMap.Set(fmt.Sprintf("key%d", i), i)
}(i)
}
wg.Wait()
fmt.Println("Готово:", safeMap.Get("key5")) // Получаем значение без гонок данных
}
sync.RWMutex
позволяет нескольким горутинам читать одновременно, но блокирует запись. type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func (s *SafeMap) Set(key string, value int) {
s.mu.Lock() // Блокируем только на запись
defer s.mu.Unlock()
s.m[key] = value
}
func (s *SafeMap) Get(key string) int {
s.mu.RLock() // Разрешаем множественное чтение
defer s.mu.RUnlock()
return s.m[key]
}
sync.Map
из стандартной библиотеки уже потокобезопасен, но работает немного медленнее обычного map
из-за внутренних механизмов. package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i, i*10) // Потокобезопасная запись
}(i)
}
wg.Wait()
val, ok := m.Load(5) // Потокобезопасное чтение
if ok {
fmt.Println("Значение:", val)
}
}
Использование канала (`chan`) вместо `map`
Вместо
map
можно передавать данные через канал (chan
), если логика позволяет. package main
import (
"fmt"
)
func main() {
ch := make(chan map[string]int, 1)
ch <- make(map[string]int)
go func() {
m := <-ch
m["key"] = 42
ch <- m
}()
m := <-ch
fmt.Println(m["key"]) // 42
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Обобщённое (generics) программирование включает:
- Параметрические типы — функции и структуры с типами-плейсхолдерами.
- Ограничения (where, extends, : T) — накладывают требования на типы.
- Обобщённые интерфейсы и классы.
- Type erasure — скрытие конкретного типа при сохранении поведения. Generics позволяют писать универсальный, повторно используемый код с типовой безопасностью.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2