Войти Регистрация
Конкурентность

23. Зоны доставки Лавки через sync.Once

Средняя

Go · 39 строк

Zone вызывается на каждый новый заказ, около 3 000 раз в секунду. Файл с полигонами весит 2 МБ, автор рассчитывал прочитать его один раз за жизнь процесса.

После выката профилировщик показал, что 40 % CPU уходит в json.Unmarshal, а заказы во всех районах получают «адрес вне зоны доставки». Отметьте строки с ошибками.

В работе: Сервис, который по даркстору отдаёт полигон его зоны доставки.

Как проверяем Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Плюс 2 вопроса про поведение программы — на зачёт не влияют. Ответ один на подход: после него показываем разбор.
sync.Onceполучатель по значениюгонка данныхобработка ошибок

Источник: наша задача на данных Яндекс Лавки: зоны доставки дарксторов. Условие пересказано своими словами.

  1. package zones
  2. import (
  3. "encoding/json"
  4. "os"
  5. "sync"
  6. )
  7. type Polygon [][2]float64
  8. type ZoneStore struct {
  9. once sync.Once
  10. zones map[string]Polygon
  11. err error
  12. }
  13. // Load читает полигоны 450 дарксторов один раз за жизнь процесса.
  14. func (s ZoneStore) Load(path string) error {
  15. var err error
  16. s.once.Do(func() {
  17. raw, e := os.ReadFile(path)
  18. if e != nil {
  19. err = e
  20. return
  21. }
  22. s.zones = make(map[string]Polygon)
  23. err = json.Unmarshal(raw, &s.zones)
  24. })
  25. return err
  26. }
  27. // Zone вызывается на каждый заказ, 3000 RPS.
  28. func (s *ZoneStore) Zone(storeID string) (Polygon, bool) {
  29. if s.zones == nil {
  30. s.Load("/etc/lavka/zones.json")
  31. }
  32. p, ok := s.zones[storeID]
  33. return p, ok
  34. }