В Go
sync.WaitGroup используется для синхронизации выполнения горутин. Она позволяет основной горутине (или любой другой горутине) ждать завершения группы горутин перед продолжением работы. Это особенно полезно, когда нужно убедиться, что все фоновые задачи завершены до выполнения дальнейших действий.Увеличивает (или уменьшает) счетчик горутин на заданное значение
delta.Обычно вызывается до запуска горутин, чтобы установить количество горутин, которые нужно дождаться.
Уменьшает счетчик горутин на 1.
Вызывается горутиной, когда она завершает свою работу.
Блокирует выполнение до тех пор, пока счетчик горутин не станет равен нулю.
Обычно вызывается основной горутиной для ожидания завершения всех горутин.
Мы используем
WaitGroup для ожидания завершения нескольких горутин.package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Уменьшает счетчик на 1 при завершении работы горутины
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1) // Увеличивает счетчик горутин на 1
go worker(i, &wg)
}
wg.Wait() // Ожидает завершения всех горутин
fmt.Println("All workers done")
}
worker.WaitGroup увеличивается на 1 перед запуском каждой горутины с помощью wg.Add(1).wg.Done() при завершении, уменьшая счетчик на 1.wg.Wait(), блокируясь до тех пор, пока все горутины не завершат свою работу.Позволяет основной горутине дождаться завершения всех запущенных горутин, что особенно важно для корректного завершения программы или выполнения зависимых задач.
Гарантирует, что основная горутина не завершит выполнение программы до того, как завершатся все горутины, предотвращая возможные дедлоки или незавершенные операции.
Позволяет легко управлять множеством горутин, не требуя сложной логики для отслеживания их завершения.
Без использования
WaitGroup основной поток может завершиться до завершения всех горутин, что приведет к неполной обработке данных. В этом примере использование time.Sleep для ожидания является ненадежным и не гарантирует завершение всех горутин. Вместо этого правильное использование WaitGroup обеспечивает корректное завершение всех задач.package main
import (
"fmt"
"time"
)
func worker(id int) {
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
for i := 1; i <= 5; i++ {
go worker(i)
}
time.Sleep(2 * time.Second) // Это не гарантирует завершение всех горутин
fmt.Println("All workers done")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Каналы потокобезопасны для отправки и получения данных, но передаваемые объекты должны быть неизменяемыми для предотвращения гонок.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Таймауты (
timeout) в HTTP-запросах предотвращают зависание приложения при медленных или недоступных серверах. Они позволяют ограничить время ожидания ответа, чтобы избежать бесконечного ожидания и высвободить ресурсы.В Golang таймауты можно устанавливать на разных уровнях:
Timeout для всего запроса (включает подключение, отправку и получение данных)
client := &http.Client{
Timeout: 5 * time.Second, // Запрос не может длиться дольше 5 секунд
}Таймаут на установку соединения
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 2 * time.Second, // 2 секунды на подключение
}).DialContext,
}
client := &http.Client{Transport: transport}Таймаут на чтение и запись
transport := &http.Transport{
ResponseHeaderTimeout: 3 * time.Second, // 3 секунды на заголовки
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
1. Оператор ... разворачивает элементы второго слайса, добавляя их к первому.
2. Новый слайс может использовать новую память, если ёмкость исходного недостаточна.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Слайсы имеют две основные характеристики: длину (len) и емкость (capacity). Понимание этих характеристик важно для эффективного использования слайсов.
Это количество элементов, которые в данный момент находятся в слайсе. Она указывает, сколько элементов доступно для чтения или записи.
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Println("Length:", len(slice)) // Length: 5
}
Это максимальное количество элементов, которые слайс может содержать без выделения дополнительной памяти. Емкость всегда больше или равна длине слайса.
package main
import "fmt"
func main() {
slice := make([]int, 3, 5)
fmt.Println("Length:", len(slice)) // Length: 3
fmt.Println("Capacity:", cap(slice)) // Capacity: 5
}
Определяет текущее количество элементов в слайсе.
Используется для операций чтения и записи.
Определяет максимальное количество элементов, которые могут быть добавлены в слайс без выделения новой памяти.
Емкость может увеличиваться автоматически при добавлении элементов через функцию
append.Когда вы добавляете элементы в слайс с помощью
append, если текущей емкости недостаточно, автоматически выделяет новый массив с большей емкостью, копирует существующие элементы в новый массив и добавляет новые элементы.package main
import "fmt"
func main() {
slice := make([]int, 2, 2)
slice[0] = 1
slice[1] = 2
fmt.Println("Before append:", slice, "Len:", len(slice), "Cap:", cap(slice)) // [1 2] Len: 2 Cap: 2
// Добавляем элемент, превышающий текущую емкость
slice = append(slice, 3)
fmt.Println("After append:", slice, "Len:", len(slice), "Cap:", cap(slice)) // [1 2 3] Len: 3 Cap: 4
}
Позволяет задать начальный индекс, конечный индекс и емкость нового слайса.
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("Length:", len(newSlice)) // 2
fmt.Println("Capacity:", cap(newSlice)) // 3
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Обладает несколькими ключевыми отличиями от Java и Python, что делает его уникальным и подходящим для определенных задач.
Go: Компилируемый язык, компилируется в машинный код, что обеспечивает высокую производительность и быстрое время выполнения.
Java: Компилируется в байт-код, который выполняется на виртуальной машине Java (JVM). Это обеспечивает переносимость, но может добавлять накладные расходы.
Python: Интерпретируемый язык, что делает его менее производительным по сравнению с компилируемыми языками.
Go: Разработан для простоты и читаемости, минимизирует синтаксическую сложность, избегает избыточности.
Java: Сложный и многословный синтаксис, требует больше кода для выполнения тех же задач.
Python: Простой и читаемый синтаксис, который делает его легким для изучения и использования.
Go: Автоматическая сборка мусора, но с управляемыми задержками для обеспечения высокой производительности.
Java: Автоматическая сборка мусора на JVM, что может приводить к задержкам в критических приложениях.
Python: Автоматическая сборка мусора с использованием подсчета ссылок и циклического сборщика мусора.
Go: Встроенная поддержка конкурентности через горутины и каналы, легковесные потоки с низкими накладными расходами.
Java: Многопоточность с использованием потоков, сложное управление потоками и синхронизацией.
Python: Поддержка многопоточности, но ограниченная глобальной блокировкой интерпретатора (GIL), что затрудняет использование многопоточности для параллельных вычислений.
Go: Статически типизированный язык, ошибки типа обнаруживаются на этапе компиляции, что повышает надежность кода.
Java: Статически типизированный язык, что позволяет обнаруживать ошибки типа на этапе компиляции.
Python: Динамически типизированный язык, типы проверяются во время выполнения, что может приводить к ошибкам времени выполнения.
Go: Использует интерфейсы для определения поведения без наследования. Интерфейсы реализуются неявно.
Java: Использует классы и интерфейсы, поддерживает множественное наследование через интерфейсы и одиночное наследование классов.
Python: Поддерживает множественное наследование классов, что может усложнять структуру программы.
Go: Богатая стандартная библиотека с встроенной поддержкой работы с сетью, веб-серверами и другими задачами.
Java: Широкая стандартная библиотека с обширной поддержкой различных API и утилит.
Python: Обширная стандартная библиотека, особенно сильная в области научных вычислений, обработки данных и веб-разработки.
Go: Современные и мощные инструменты для сборки, тестирования и профилирования. Простая система управления зависимостями.
Java: Зрелая экосистема с множеством фреймворков и инструментов (например, Maven, Gradle, Spring).
Python: Обширная экосистема пакетов и библиотек (например, pip, virtualenv, Django).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Каждая горутина получает отдельный стек, который при старте весит около 2 килобайт. Он динамически увеличивается по мере необходимости (до мегабайт), а при простое — может быть сокращён.
Таким образом, память для горутины не аллоцируется в куче сразу, а используется адаптивно.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6🔥1
Массив (array) — это структура данных, которая представляет собой фиксированную последовательность элементов одного типа. Все элементы массива размещены в памяти последовательно и имеют одинаковый тип. Используются для хранения коллекций данных, где количество элементов заранее известно и фиксировано.
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
Все элементы массива имеют один и тот же тип.
Элементы массива хранятся последовательно в памяти, что обеспечивает быстрый доступ к любому элементу по индексу.
Массивы объявляются с указанием типа элементов и фиксированного размера:
var arr [5]int
Могут быть инициализированы при объявлении:
arr := [5]int{1, 2, 3, 4, 5}Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}Осуществляется с использованием индексов, начиная с 0:
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции
len:fmt.Println(len(arr)) // 5
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]Копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}
arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]С помощью оператора
==, если они имеют одинаковую длину и тип элементов:arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{4, 5, 6}
fmt.Println(arr1 == arr2) // true
fmt.Println(arr1 == arr3) // falseПример
package main
import (
"fmt"
)
func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}
// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1
// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]
// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5
// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]
// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}
func modifyArray(a [5]int) {
a[0] = 10
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
SSL (Secure Sockets Layer) — это протокол, который обеспечивает безопасность передачи данных в интернете, используя шифрование. Он был разработан для защиты данных, передаваемых между клиентом (например, веб-браузером) и сервером (например, веб-сайтом), от перехвата и манипуляций.
Защита данных от перехвата и чтения посторонними лицами путем их шифрования.
Подтверждение подлинности сервера (и иногда клиента) с помощью цифровых сертификатов, что позволяет клиенту убедиться, что он подключен к настоящему серверу.
Проверка того, что данные не были изменены во время передачи, с помощью контрольных сумм и хеш-функций.
Клиент инициирует соединение с сервером, запрашивая защищенное соединение.
Сервер отправляет свой цифровой сертификат, который содержит его публичный ключ и информацию о сервере.
Клиент проверяет сертификат, используя доверенные центры сертификации (CA), чтобы удостовериться в подлинности сервера.
Клиент и сервер используют асимметричное шифрование для обмена ключами сеанса, которые затем используются для симметричного шифрования данных в течение сессии.
Все данные, передаваемые между клиентом и сервером, шифруются с использованием симметричных ключей, обеспечивая безопасность передачи.
При посещении веб-сайта с использованием HTTPS (например, https://example.com), SSL обеспечивает шифрование и безопасность данных, передаваемых между вашим браузером и сервером.
Никогда не был выпущен публично из-за серьезных уязвимостей.
Выпущен в 1995 году, но вскоре был признан небезопасным из-за множества уязвимостей.
Выпущен в 1996 году, значительно улучшил безопасность, но со временем также был признан устаревшим из-за уязвимостей (например, POODLE-атака).
SSL был заменен протоколом TLS, который является его преемником и предлагает улучшенную безопасность. Текущие версии TLS (1.2 и 1.3) используются вместо SSL.
TLS обеспечивает более сильное шифрование, лучшее управление сессионными ключами и устранение уязвимостей, найденных в SSL.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В 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
👍2🔥2
Forwarded from Идущий к IT
🔥 Записал видос "Как за 3 минуты настроить Автоотклики на вакансии HeadHunter" больше не придется заниматься этой унылой рутиной
📺 Видео: https://youtu.be/G_FOwEGPwlw
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Интерфейс состоит из двух частей: указателя на динамический тип и указателя на данные, связанные с этим типом. Такая структура позволяет интерфейсу хранить и управлять значениями разных типов динамически.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1