Race-детектор в Go на простом примере | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
Team Lead Архитектура и шаблоны проектирования Разработчик IoT C# Developer. Professional PostgreSQL Подготовка к сертификации Oracle Java Programmer (OCAJP) C# ASP.NET Core разработчик
-5%
Kotlin Backend Developer
-8%
iOS Developer. Professional
-8%
Symfony Framework Unity Game Developer. Basic JavaScript Developer. Professional Android Developer. Basic JavaScript Developer. Basic Java Developer. Professional Highload Architect Reverse-Engineering. Professional Java Developer. Basic PHP Developer. Professional Алгоритмы и структуры данных Framework Laravel Cloud Solution Architecture Vue.js разработчик Интенсив «Оптимизация в Java» Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Супер-интенсив "Tarantool" PHP Developer. Basic
Инфраструктура
Мониторинг и логирование: Zabbix, Prometheus, ELK Дизайн сетей ЦОД Разработчик IoT PostgreSQL Экспресс-курс "Версионирование и командная работа с помощью Git"
-30%
Экспресс-курс «Введение в непрерывную поставку на базе Docker» Базы данных Reverse-Engineering. Professional Administrator Linux. Professional Network engineer Cloud Solution Architecture Внедрение и работа в DevSecOps Супер-практикум по работе с протоколом BGP Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Супер-интенсив «СУБД в высоконагруженных системах» Супер-интенсив "Tarantool" Network engineer. Basic
Корпоративные курсы
Безопасность веб-приложений IT-Recruiter Дизайн сетей ЦОД Компьютерное зрение Разработчик IoT Вебинар CERTIPORT Machine Learning. Professional
-6%
NoSQL Пентест. Практика тестирования на проникновение Java QA Engineer. Базовый курс Руководитель поддержки пользователей в IT
-8%
SRE практики и инструменты Cloud Solution Architecture Внедрение и работа в DevSecOps Супер-практикум по работе с протоколом BGP Infrastructure as a code Супер-практикум по использованию и настройке GIT Промышленный ML на больших данных Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» BPMN: Моделирование бизнес-процессов Основы Windows Server
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Race-детектор в Go на простом примере

Go_Deep_22.1-5020-623cfd.png

Golang в своём арсенале имеет такую вещь, как race detector.

Посмотрим на следующий код:

type Cache struct {
        data map[string]int
}

func NewCache() *Cache {
        return &Cache{
                data: make(map[string]int),
        }
}

func (c *Cache) Set(k string, v int) {
        c.data[k] = v
}

func (c *Cache) Get(k string) int {
        if v, ok := c.data[k]; ok {
                return v
        }
        return 0
}

Это возможная реализация простейшего кэша, у которого ключ — это строка, а значение — целое число.

Всё будет хорошо до тех пор, пока кэш используется неконкурентно. Как только речь заходит о чём-то асинхронном (нужно заметить, что язык go отлично для этого подходит), — тут могут появиться неожиданные сюрпризы.

Взглянем на использование нашего кэша:

c := NewCache()

var wg sync.WaitGroup

wg.Add(1)
go func() {
        defer wg.Done()
        for i := 0; i < 1000; i++ {
                c.Set("nick", 25)
        }
}()

wg.Add(1)
go func() {
        defer wg.Done()
        for i := 0; i < 1000; i++ {
                c.Set("nick", 30)
        }
}()

wg.Wait()

fmt.Println(c.Get("nick"))

Код вполне валидный с точки зрения языка, он компилируется, 2 корутины обновляют значение по ключу nick.

Что выведет программа?

Вариантов несколько: 1) иногда мы можем увидеть 25; 2) иногда мы можем увидеть 30; 3) иногда наше приложение может упасть с ошибкой fatal error: concurrent map writes.

Для того, чтобы найти проблему в нашем примере, достаточно воспользоваться ключем -race при сборке.

Тогда при запуске мы увидим предупреждение следующего вида:

==================
WARNING: DATA RACE
Write at 0x00c00009c150 by goroutine 8:
  runtime.mapassign_faststr()
      /usr/lib/go-1.13/src/runtime/map_faststr.go:202 +0x0
  main.main.func2()
      /home/yury/race.go:19 +0xb7

Previous write at 0x00c00009c150 by goroutine 7:
  runtime.mapassign_faststr()
      /usr/lib/go-1.13/src/runtime/map_faststr.go:202 +0x0
  main.main.func1()
      /home/yury/race.go:19 +0xb7
...

Советую периодически использовать флаг -race для выявления проблем с гонками. В продакшене же он существенно замедляет работу вашего приложения и не рекомендуется.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться