Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Идущий к IT
Твое резюме на HeadHunter — ОК, если ты видишь это.
HeadHunter сравнивает ключевые навыки в твоем резюме и в вакансии и в момент отклика отображает, насколько % ты соответствуешь требованиям.
Специальный бейджик «Подходит по навыкам на 100%» отображается, если соответствие составляет более 60%.
Если при просмотре вакансий ты видишь такой бейджик, это значит, что список навыков в твоем резюме качественно составлен.
Это важный параметр, так как рекрутерам чаще показываются резюме с лучшим соответствием.
О том, как правильно указывать ключевые навыки и оптимизировать свое резюме я уже рассказывал в этом видео
HeadHunter сравнивает ключевые навыки в твоем резюме и в вакансии и в момент отклика отображает, насколько % ты соответствуешь требованиям.
Специальный бейджик «Подходит по навыкам на 100%» отображается, если соответствие составляет более 60%.
Если при просмотре вакансий ты видишь такой бейджик, это значит, что список навыков в твоем резюме качественно составлен.
Это важный параметр, так как рекрутерам чаще показываются резюме с лучшим соответствием.
О том, как правильно указывать ключевые навыки и оптимизировать свое резюме я уже рассказывал в этом видео
Мапы (карты) не являются потокобезопасными по умолчанию, что означает, что одновременное чтение и запись в мапу из нескольких горутин может привести к состояниям гонки, некорректным данным и паникам. Давайте рассмотрим, как можно обеспечить потокобезопасность при работе с мапами.
Если несколько горутин одновременно пытаются читать и изменять мапу, возникает конкуренция за доступ к данным, что приводит к непредсказуемому поведению программы. Это может включать утечки данных, несогласованность данных и даже крах программы.
Один из наиболее простых и распространенных способов обеспечить потокобезопасность — использование мьютексов (
sync.Mutex
). В этом примере мьютекс используется для защиты операций записи и чтения, обеспечивая эксклюзивный доступ к мапе.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Если ожидается частое чтение и редкие записи, можно использовать
sync.RWMutex
, который позволяет множественное чтение, но блокирует доступ на запись. Здесь RWMutex
позволяет параллельное чтение, но блокирует все операции на запись, что улучшает производительность при частых чтениях.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.RLock()
defer mu.RUnlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Go предоставляет пакет
sync.Map
, который изначально создан для конкурентного использования. sync.Map
автоматически обеспечивает потокобезопасность для операций чтения, записи и удаления.package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
m.Store("key1", 42)
}()
go func() {
defer wg.Done()
value, _ := m.Load("key1")
fmt.Println(value)
}()
wg.Wait()
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Проектировался с учетом простоты и производительности, и одно из решений разработчиков — не делать мапы (карты) потокобезопасными по умолчанию.
Потокобезопасность требует дополнительных накладных расходов для синхронизации доступа к данным. Если бы мапы в Go были потокобезопасными по умолчанию, каждый доступ к мапе был бы медленнее из-за необходимости блокировок. Большинство операций с мапами в реальных приложениях не требуют потокобезопасности, так как часто они выполняются в одном потоке или используются мапы, которые не модифицируются одновременно.
Go следует философии явного управления, где программисты сами должны решать, когда и как использовать синхронизацию. Это позволяет более точно контролировать производительность и обеспечивает гибкость при проектировании многопоточных приложений.
Потокобезопасные структуры данных, такие как
sync.Map
, могут быть сложными для понимания и использования. Введение потокобезопасности по умолчанию усложнило бы стандартные мапы, делая их менее интуитивными и простыми для использования.Эти мьютексы позволяют программистам вручную управлять синхронизацией доступа к мапам.
sync.Mutex
используется для блокировки доступа при чтении и записи, а sync.RWMutex
позволяет параллельное чтение и эксклюзивную запись.var mu sync.Mutex
m := make(map[string]int)
// запись с блокировкой
mu.Lock()
m["key"] = 42
mu.Unlock()
// чтение с блокировкой
mu.Lock()
value := m["key"]
mu.Unlock()
Специальная структура данных, которая изначально спроектирована для безопасного использования в многопоточной среде.
sync.Map
оптимизирован для сценариев с частыми чтениями и редкими записями.var m sync.Map
m.Store("key", 42)
value, ok := m.Load("key")
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Каналы изначально проектировались как потокобезопасные средства для коммуникации между горутинами. Однако, несмотря на их встроенную потокобезопасность, есть определенные правила и ограничения, которые необходимо учитывать для корректного использования каналов.
Каналы безопасны для использования из нескольких горутин. Это означает, что вы можете отправлять данные в канал из одной горутины и получать данные из другой горутины без дополнительной синхронизации.
package main
import (
"fmt"
"sync"
)
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
ch <- 42
}()
go func() {
defer wg.Done()
value := <-ch
fmt.Println(value)
}()
wg.Wait()
}
Несколько горутин могут безопасно отправлять данные в один и тот же канал.
package main
import (
"fmt"
"sync"
)
func main() {
ch := make(chan int, 2)
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
ch <- 1
}()
go func() {
defer wg.Done()
ch <- 2
}()
go func() {
defer wg.Done()
for i := 0; i < 2; i++ {
fmt.Println(<-ch)
}
}()
wg.Wait()
}
Несколько горутин могут безопасно получать данные из одного и того же канала.
package main
import (
"fmt"
"sync"
)
func main() {
ch := make(chan int, 2)
var wg sync.WaitGroup
ch <- 1
ch <- 2
wg.Add(2)
go func() {
defer wg.Done()
fmt.Println(<-ch)
}()
go func() {
defer wg.Done()
fmt.Println(<-ch)
}()
wg.Wait()
}
Канал должен закрываться только одной горутиной, и закрытие канала из нескольких горутин одновременно приведет к панике.
package main
func main() {
ch := make(chan int)
go func() {
close(ch) // Это допустимо
}()
go func() {
close(ch) // Это приведет к панике
}()
}
Попытка отправки данных в закрытый канал также вызовет панику. Поэтому, перед отправкой данных необходимо убедиться, что канал не закрыт.
package main
func main() {
ch := make(chan int)
close(ch)
ch <- 42 // Это приведет к панике
}
Если одна горутина закрывает канал, другая горутина может получить нулевое значение при чтении из него, что может привести к неправильным выводам, если это не предусмотрено.
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
close(ch)
}()
value, ok := <-ch
if !ok {
fmt.Println("Канал закрыт")
} else {
fmt.Println(value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Использование слайсов в многопоточном (concurrent) контексте в Go требует особого внимания к потокобезопасности. По умолчанию слайсы не являются потокобезопасными, что означает, что одновременное чтение и запись в слайс из нескольких горутин может привести к состояниям гонки, некорректным данным и паникам. Давайте рассмотрим, насколько безопасно использовать слайсы в условиях concurrency и какие подходы позволяют обеспечить безопасность.
Если несколько горутин одновременно изменяют содержимое слайса или его длину, это может привести к состояниям гонки и повреждению данных.
При добавлении элементов в слайс его размер может увеличиваться, что может привести к перераспределению памяти и копированию содержимого, создавая потенциальные проблемы при одновременном доступе.
Если слайс используется только для чтения, его можно безопасно использовать из нескольких горутин.
package main
import (
"fmt"
"sync"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
for _, v := range slice {
wg.Add(1)
go func(val int) {
defer wg.Done()
fmt.Println(val)
}(v)
}
wg.Wait()
}
Если каждая горутина должна иметь независимую копию слайса, передавайте копию в каждую горутину.
package main
import (
"fmt"
"sync"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
for _, v := range slice {
wg.Add(1)
go func(val int) {
defer wg.Done()
fmt.Println(val)
}(v)
}
wg.Wait()
}
Для обеспечения безопасного одновременного чтения и записи используйте механизмы синхронизации, такие как мьютексы.
package main
import (
"fmt"
"sync"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
for _, v := range slice {
wg.Add(1)
go func(val int) {
defer wg.Done()
fmt.Println(val)
}(v)
}
wg.Wait()
}
В некоторых случаях лучше использовать структуры данных, которые изначально проектированы для потокобезопасного доступа, такие как
sync.Map
для мап или специальные библиотеки для потокобезопасных коллекций.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Нет, карты (maps) в Go не являются потокобезопасными по умолчанию. Использование карты в нескольких горутинах без должной синхронизации может привести к состояниям гонки, некорректным данным и паникам. Давайте рассмотрим более детально, почему это так и как можно обеспечить потокобезопасность при работе с картами в многопоточной среде.
Карты в Go разработаны для обеспечения высокой производительности при использовании в однопоточных сценариях. Если несколько горутин одновременно пытаются читать и изменять карту, возникает конкуренция за доступ к данным, что может привести к следующим проблемам:
Одновременный доступ к карте из нескольких горутин может привести к состояниям гонки, когда порядок выполнения операций непредсказуем.
Одновременное изменение структуры карты, например добавление или удаление элементов, может вызвать панику в программе.
Самый распространенный способ синхронизации доступа к карте — использование
sync.Mutex
. Мьютексы позволяют заблокировать доступ к карте на время чтения или записи.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Если в вашей программе чаще происходят операции чтения, чем записи, можно использовать
sync.RWMutex
, который позволяет нескольким горутинам читать данные одновременно, но обеспечивает эксклюзивный доступ для записи.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.RLock()
defer mu.RUnlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Go предоставляет специальную структуру
sync.Map
, которая изначально создана для безопасного использования в многопоточной среде. Она автоматически обеспечивает синхронизацию операций.package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
m.Store("key1", 42)
}()
go func() {
defer wg.Done()
value, _ := m.Load("key1")
fmt.Println(value)
}()
wg.Wait()
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Каналы в Go являются потокобезопасными, но это не означает, что они полностью освобождены от правил и ограничений при работе в многопоточной среде. Давайте разберем, насколько безопасны каналы и какие практики нужно соблюдать при их использовании.
Каналы в Go предназначены для безопасного обмена данными между горутинами. Они обеспечивают синхронизацию отправки и получения данных, что делает их безопасными для использования в многопоточной среде. Однако существуют важные моменты, которые необходимо учитывать:
Каналы потокобезопасны для операций отправки и получения. Это означает, что несколько горутин могут безопасно отправлять данные в канал и получать данные из канала одновременно.
package main
import (
"fmt"
"sync"
)
func main() {
ch := make(chan int)
var wg sync.WaitGroup
// Горутина для отправки данных
wg.Add(1)
go func() {
defer wg.Done()
ch <- 42
}()
// Горутина для получения данных
wg.Add(1)
go func() {
defer wg.Done()
value := <-ch
fmt.Println(value)
}()
wg.Wait()
}
Закрытие канала должно выполняться только одной горутиной. Попытка закрытия канала из нескольких горутин может привести к панике.
package main
func main() {
ch := make(chan int)
// Правильный способ закрытия канала
go func() {
close(ch)
}()
// Неправильный способ (может вызвать панику)
// go func() {
// close(ch)
// }()
}
Отправка данных в закрытый канал вызывает панику, поэтому необходимо быть уверенным, что канал не закрыт перед отправкой данных.
package main
func main() {
ch := make(chan int)
close(ch)
// Попытка отправки данных в закрытый канал вызовет панику
// ch <- 42
}
Чтение из закрытого канала безопасно. При чтении из закрытого канала, если канал пуст, будет возвращено нулевое значение типа и флаг, указывающий на закрытие канала.
package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
value, ok := <-ch
fmt.Println(value, ok) // Вывод: 0 false
}
Буферизованные каналы позволяют отправлять несколько значений без блокировки, пока буфер не заполнится, что может улучшить производительность.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
}
Не используйте каналы, если простое использование мьютексов или других средств синхронизации подходит лучше. Каналы предназначены для передачи данных между горутинами, а не для синхронизации доступа к общей памяти.
Если канал должен быть закрыт, делайте это только после того, как все отправляющие горутины завершат свою работу.
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
for value := range ch {
fmt.Println(value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
При работе с мьютексами в Go балансируйте Lock и Unlock (используйте defer), минимизируйте время удержания мьютекса и применяйте RLock для чтения в sync.RWMutex для повышения параллелизма.
Мьютексы (
sync.Mutex
) предназначены для обеспечения эксклюзивного доступа к общим ресурсам. Используйте мьютекс, чтобы защитить критические секции кода, которые обращаются к общим данным.var mu sync.Mutex
var sharedResource int
func updateResource(value int) {
mu.Lock()
sharedResource = value
mu.Unlock()
}
Всегда вызывайте
mu.Lock()
перед доступом к общему ресурсу и mu.Unlock()
сразу после завершения работы с ним. Это гарантирует, что доступ к ресурсу будет синхронизирован.mu.Lock()
// доступ к общему ресурсу
sharedResource = 42
mu.Unlock()
Используйте
defer
для вызова mu.Unlock()
сразу после блокировки. Это поможет избежать забывчивости в случае возврата из функции или возникновения ошибок.mu.Lock()
defer mu.Unlock()
sharedResource = 42
Взаимные блокировки могут возникать, если несколько горутин заблокированы, ожидая освобождения мьютексов друг от друга. Чтобы избежать этого, всегда соблюдайте единый порядок блокировок и разблокировок.
var mu1, mu2 sync.Mutex
func funcA() {
mu1.Lock()
defer mu1.Unlock()
mu2.Lock()
defer mu2.Unlock()
// доступ к ресурсам, защищенным mu1 и mu2
}
func funcB() {
mu2.Lock()
defer mu2.Unlock()
mu1.Lock()
defer mu1.Unlock()
// доступ к ресурсам, защищенным mu1 и mu2
}
Старайтесь минимизировать время, в течение которого держится блокировка, чтобы уменьшить вероятность конфликтов и повысить производительность.
mu.Lock()
// Минимально необходимый код для работы с защищенным ресурсом
temp := sharedResource
mu.Unlock()
// Дальнейшая обработка вне критической секции
process(temp)
Избегайте выполнения длительных операций внутри критической секции, чтобы не блокировать другие горутины.
mu.Lock()
temp := sharedResource
mu.Unlock()
// Выполнение длительных операций вне блокировки
longRunningOperation(temp)
Никогда не пытайтесь заблокировать мьютекс, который уже заблокирован текущей горутиной, так как это приведет к взаимной блокировке.
mu.Lock()
// Код
// mu.Lock() // Это приведет к взаимной блокировке
mu.Unlock()
Несколько горутин безопасно увеличивают общий счетчик с использованием мьютекса.
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
wg sync.WaitGroup
)
func increment() {
defer wg.Done()
for i := 0; i < 1000; i++ {
mu.Lock()
counter++
mu.Unlock()
}
}
func main() {
wg.Add(2)
go increment()
go increment()
wg.Wait()
fmt.Println("Final Counter:", counter)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Go конструкция
select
используется для обработки операций с каналами. Она позволяет горутинам ждать событий на нескольких каналах одновременно. Аналогом конструкции default
в select
является опция, позволяющая избежать блокировки, если ни один из каналов не готов.Когда
select
выполняется, он блокируется до тех пор, пока один из его case-блоков не станет готов к выполнению (т.е. канал не станет доступным для отправки или получения данных). Однако, если добавить блок default
, select
может выполнить его немедленно, если ни один из других case-блоков не готов. Это позволяет избежать блокировки горутины.Мы используем
select
с default
, чтобы выполнить неблокирующие операции с каналами.package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(2 * time.Second)
ch1 <- 1
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- 2
}()
for i := 0; i < 3; i++ {
select {
case val := <-ch1:
fmt.Println("Received from ch1:", val)
case val := <-ch2:
fmt.Println("Received from ch2:", val)
default:
fmt.Println("No channel is ready")
time.Sleep(500 * time.Millisecond)
}
}
}
ch1
и ch2
.select
с default
, который проверяет готовность каналов каждые 500 миллисекунд.default
, выводящий сообщение "No channel is ready".Если вы хотите проверить наличие данных на канале или возможность отправки данных без блокировки, используйте
default
.В некоторых случаях
default
может предотвратить дедлоки, позволяя горутине продолжить выполнение, даже если каналы временно недоступны.Можно использовать
default
для периодической проверки состояния канала или выполнения задач в ожидании готовности каналов.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
sync.Map
в Go — это потокобезопасная структура данных, предназначенная для конкурентного доступа к ключам и значениям, которая была введена в Go 1.9. Она предоставляет удобные методы для работы с картой в многопоточной среде без необходимости вручную управлять блокировками.sync.Map
изначально спроектирована для безопасного использования в многопоточной среде. Все операции по чтению, записи и удалению синхронизированы.sync.Map
предоставляет высокоуровневые методы для работы с картой, что упрощает её использование в сравнении с традиционными картами и мьютексами.Сохраняет значение по заданному ключу. Если ключ уже существует, его значение будет перезаписано.
var m sync.Map
m.Store("foo", 1)
Возвращает значение, сохраненное по заданному ключу, и булев флаг, указывающий, было ли найдено значение.
value, ok := m.Load("foo")
if ok {
fmt.Println("Found:", value)
} else {
fmt.Println("Not found")
}
Возвращает существующее значение по ключу, если ключ уже существует, иначе сохраняет и возвращает новое значение. Булев флаг указывает, существовал ли ключ до вызова.
actual, loaded := m.LoadOrStore("foo", 1)
if loaded {
fmt.Println("Existing value:", actual)
} else {
fmt.Println("Stored new value:", actual)
}
Удаляет значение по заданному ключу.
m.Delete("foo")
Выполняет функцию для каждого ключа и значения в карте. Если функция возвращает
false
, обход прекращается.m.Store("foo", 1)
m.Store("bar", 2)
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true // продолжить обход
})
Несколько горутин безопасно работают с
sync.Map
.package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
// Запись в sync.Map из нескольких горутин
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i, i*i)
}(i)
}
wg.Wait()
// Чтение из sync.Map
m.Range(func(key, value interface{}) bool {
fmt.Printf("key: %v, value: %v\n", key, value)
return true
})
}
sync.Map
оптимизирована для сценариев с частыми операциями чтения и редкими операциями записи. Она может быть менее эффективной при частых изменениях структуры карты.Если нужно использовать карту в многопоточной среде и не хочется вручную управлять блокировками с помощью мьютексов.
sync.Map
может сделать код более понятным и простым за счет использования высокоуровневых методов вместо ручного управления блокировками.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM