Ответ
Основное различие заключается в потокобезопасности и сценариях использования.
map
(стандартная мапа)
Это встроенный тип данных в Go. Он не является потокобезопасным. Попытка одновременной записи или чтения и записи из разных горутин без дополнительной синхронизации (например, мьютекса) приведёт к панике fatal error: concurrent map read and map write
.
- Преимущества: Максимальная производительность в однопоточных сценариях.
- Недостатки: Требует ручной синхронизации для конкурентного доступа.
sync.Map
Это специальная реализация мапы из пакета sync
, которая является потокобезопасной. Однако она спроектирована и оптимизирована для очень специфичного сценария использования:
- Ключи, однажды записанные в мапу, в основном только читаются и крайне редко изменяются или удаляются.
- Разные горутины преимущественно работают с разными наборами ключей, что снижает внутреннюю конкуренцию.
- Преимущества: Потокобезопасность "из коробки". Высокая производительность в сценариях "записал один раз, читай много раз" (например, кэши).
- Недостатки: Медленнее, чем
map
с мьютексом, в сценариях со смешанной или частой записью. Более сложный API (Store
,Load
,LoadOrStore
,Delete
).
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
// Запись значения (потокобезопасно)
m.Store("city", "Moscow")
// Чтение значения (потокобезопасно)
// `Load` возвращает `interface{}` и `bool` (был ли ключ найден)
value, ok := m.Load("city")
if ok {
fmt.Println(value.(string)) // Вывод: Moscow
}
// Удаление
m.Delete("city")
}
Альтернатива: map
+ sync.RWMutex
Для большинства общих задач, где требуется потокобезопасная мапа с частыми записями и чтениями, лучшим выбором является стандартная map
, защищённая мьютексом sync.RWMutex
. Это даёт более предсказуемую производительность и является идиоматичным решением в Go.
Когда что использовать:
map
: Если доступ к мапе осуществляется только из одной горутины.map + sync.RWMutex
: Для большинства общих случаев, когда нужна потокобезопасная мапа (смешанные чтение/запись).sync.Map
: В нишевых сценариях с высокой конкуренцией, где данные преимущественно читаются (например, кэш метаданных, который редко обновляется).