Как поделиться картой через горутины

Я пытаюсь закодировать структуру уведомлений в Go, которая будет содержать серию ключей и их соответствующие значения и будет запускать уведомление, если значение упадет ниже порогового значения.

уведомление должно срабатывать только один раз, когда первая выборка падает ниже порогового значения, а последующие выборки ниже этого значения не должны срабатывать снова, ПОКА значение не поднимется выше порога.

например, скажем, мой порог равен 10, и я отправляю образцы из 15, 14, 11, 10, … 9. после отправки 9 должно запускаться уведомление. дальнейшие пробы 8, 7, 4 не должны вызывать никакого эффекта. следующие образцы, такие как 5, 6, 7, 9, 10, 11, 14, 30, не должны ничего делать. как только образец снова упадет ниже 10:30, 20, 15, 10, 7 … необходимо отправить другое уведомление.

У меня проблема, когда несколько горутин манипулируют моей структурой.

Я пробовал синхронизировать с помощью sync.Mutex и ТАКЖЕ использовать sync.Map, но безуспешно. Я чувствую, что где-то есть справочная копия или кеширование, но я слишком новичок в Go, чтобы найти проблему.

для этого я создал такую ​​структуру:

type Notifier interface { Send(message string) } type NotificationBoard struct { mutex sync.Mutex Last sync.Map notifier Notifier } func (n *NotificationBoard) Init(notifier Notifier) { n.notifier = notifier } // NotifyLess … func (n *NotificationBoard) NotifyLess(key string, value, threshold float64) { n.mutex.Lock() defer n.mutex.Unlock() if value >= threshold { fmt.Printf(«NotificationBoard.NotifyLess %v (value >= threshold): %v >= %vn», key, value, threshold) n.Last.Store(key, value) return } // value < threshold if last, found := n.Last.Load(key); found == true { fmt.Printf(«NotificationBoard.NotifyLess %v (value < threshold): %v < %v : found %vn», key, value, threshold, last) if last.(float64) >= threshold { // first trigger n.notifier.Send(fmt.Sprintf(«%s < %v (%v)», key, threshold, value)) } } else { fmt.Printf(«NotificationBoard.NotifyLess %v (value < threshold): %v < %v : not foundn», key, value, threshold) // not found, started board as less n.notifier.Send(fmt.Sprintf(«%s < %v (%v)», key, threshold, value)) } n.Last.Store(key, value) return }

Я знаю, что этого должно быть достаточно, используя sync.Mutex ИЛИ sync.Map, но в приведенном выше коде есть и то, и другое, потому что это моя текущая (сломанная) версия.

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

type dummy struct{} func (d *dummy) Send(message string) { fmt.Println(«—————> notifying», message) } func newBoard() *NotificationBoard { notificationBoard := &NotificationBoard{} notificationBoard.Init(&dummy{}) return notificationBoard }

Я также добавил несколько трассировок fmt.Println (не включенных в мой код выше для краткости) и сначала подготовил тест с одним гуру (который работает, как ожидалось):

func Test1(t *testing.T) { board := newBoard() board.NotifyLess(«k1», 15, 10) board.NotifyLess(«k1», 10, 10) board.NotifyLess(«k1», 5, 10) board.NotifyLess(«k1», 4, 10) board.NotifyLess(«k1», 3, 10) board.NotifyLess(«k1», 10, 10) board.NotifyLess(«k1», 15, 10) board.NotifyLess(«k1», 20, 10) board.NotifyLess(«k1», 15, 10) board.NotifyLess(«k1», 10, 10) board.NotifyLess(«k1», 5, 10) board.NotifyLess(«k1», 1, 10) }

выходы:

> go test -run Test1 NotificationBoard.NotifyLess k1 (value >= threshold): 15 >= 10 NotificationBoard.NotifyLess k1 (value >= threshold): 10 >= 10 NotificationBoard.NotifyLess k1 (value < threshold): 5 < 10 : found 10 —————> notifying k1 < 10 (5) NotificationBoard.NotifyLess k1 (value < threshold): 4 < 10 : found 5 NotificationBoard.NotifyLess k1 (value < threshold): 3 < 10 : found 4 NotificationBoard.NotifyLess k1 (value >= threshold): 10 >= 10 NotificationBoard.NotifyLess k1 (value >= threshold): 15 >= 10 NotificationBoard.NotifyLess k1 (value >= threshold): 20 >= 10 NotificationBoard.NotifyLess k1 (value >= threshold): 15 >= 10 NotificationBoard.NotifyLess k1 (value >= threshold): 10 >= 10 NotificationBoard.NotifyLess k1 (value < threshold): 5 < 10 : found 10 —————> notifying k1 < 10 (5) NotificationBoard.NotifyLess k1 (value < threshold): 1 < 10 : found 5 PASS

мы видим, что вывод «notifying ….» происходит дважды, только в моменты, когда выборка опускается ниже порогового значения.

но затем я создал тест с несколькими гоурутинами, и затем уведомления появляются несколько раз:

func Test3(t *testing.T) { preparing := sync.WaitGroup{} preparing.Add(1) board := newBoard() wg := sync.WaitGroup{} for i := 0; i < 30; i++ { wg.Add(1) go func(x int, not *NotificationBoard) { fmt.Printf(«routine %v waiting preparation… n», x) preparing.Wait() for j := 15.0; j > 5; j— { fmt.Printf(«routine %v notifying %vn», x, j) not.NotifyLess(«keyX», j+float64(x+1)/100, 10) } wg.Done() }(i, board) } preparing.Done() wg.Wait() }

который выводит:

> go test -run Test3 routine 7 waiting preparation… routine 2 waiting preparation… routine 2 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.03 >= 10 routine 2 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.03 >= 10 routine 2 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.03 >= 10 routine 2 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.03 >= 10 routine 2 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.03 >= 10 routine 2 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.03 >= 10 routine 2 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.03 < 10 : found 10.03 —————> notifying keyX < 10 (9.03) routine 2 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.03 < 10 : found 9.03 routine 2 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.03 < 10 : found 8.03 routine 2 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.03 < 10 : found 7.03 routine 14 waiting preparation… routine 14 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.15 >= 10 routine 14 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.15 >= 10 routine 14 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.15 >= 10 routine 14 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.15 >= 10 routine 14 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.15 >= 10 routine 14 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.15 >= 10 routine 14 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.15 < 10 : found 10.15 —————> notifying keyX < 10 (9.15) routine 14 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.15 < 10 : found 9.15 routine 14 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.15 < 10 : found 8.15 routine 14 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.15 < 10 : found 7.15 routine 22 waiting preparation… routine 27 waiting preparation… routine 27 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.28 >= 10 routine 27 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.28 >= 10 routine 27 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.28 >= 10 routine 27 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.28 >= 10 routine 27 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.28 >= 10 routine 27 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.28 >= 10 routine 27 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.28 < 10 : found 10.28 —————> notifying keyX < 10 (9.28) routine 27 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.28 < 10 : found 9.28 routine 27 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.28 < 10 : found 8.28 routine 27 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.28 < 10 : found 7.28 routine 20 waiting preparation… routine 20 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.21 >= 10 routine 20 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.21 >= 10 routine 20 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.21 >= 10 routine 20 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.21 >= 10 routine 20 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.21 >= 10 routine 20 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.21 >= 10 routine 20 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.21 < 10 : found 10.21 —————> notifying keyX < 10 (9.21) routine 20 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.21 < 10 : found 9.21 routine 20 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.21 < 10 : found 8.21 routine 20 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.21 < 10 : found 7.21 routine 19 waiting preparation… routine 19 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.2 >= 10 routine 19 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.2 >= 10 routine 19 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.2 >= 10 routine 19 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.2 >= 10 routine 19 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.2 >= 10 routine 19 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.2 >= 10 routine 19 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.2 < 10 : found 10.2 —————> notifying keyX < 10 (9.2) routine 19 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.2 < 10 : found 9.2 routine 19 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.2 < 10 : found 8.2 routine 19 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.2 < 10 : found 7.2 routine 0 waiting preparation… routine 0 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.01 >= 10 routine 0 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.01 >= 10 routine 0 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.01 >= 10 routine 0 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.01 >= 10 routine 0 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.01 >= 10 routine 0 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.01 >= 10 routine 0 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.01 < 10 : found 10.01 —————> notifying keyX < 10 (9.01) routine 0 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.01 < 10 : found 9.01 routine 0 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.01 < 10 : found 8.01 routine 0 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.01 < 10 : found 7.01 routine 17 waiting preparation… routine 17 notifying 15 NotificationBoard.NotifyLess keyX (value >= threshold): 15.18 >= 10 routine 17 notifying 14 NotificationBoard.NotifyLess keyX (value >= threshold): 14.18 >= 10 routine 17 notifying 13 NotificationBoard.NotifyLess keyX (value >= threshold): 13.18 >= 10 routine 17 notifying 12 NotificationBoard.NotifyLess keyX (value >= threshold): 12.18 >= 10 routine 17 notifying 11 NotificationBoard.NotifyLess keyX (value >= threshold): 11.18 >= 10 routine 17 notifying 10 NotificationBoard.NotifyLess keyX (value >= threshold): 10.18 >= 10 routine 17 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.18 < 10 : found 10.18 —————> notifying keyX < 10 (9.18) routine 17 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 8.18 < 10 : found 9.18 routine 17 notifying 7 NotificationBoard.NotifyLess keyX (value < threshold): 7.18 < 10 : found 8.18 routine 17 notifying 6 NotificationBoard.NotifyLess keyX (value < threshold): 6.18 < 10 : found 7.18 routine 15 waiting preparation… routine 16 waiting preparation… …… continues

Я добавил десятичное значение для представления горутины, и, глядя на результат, казалось, что у каждой горутины была собственная копия карты, поскольку они находили предыдущее значение с теми же десятичными разрядами. но потом я обнаружил:

… NotificationBoard.NotifyLess keyX (value >= threshold): 10.22 >= 10 routine 21 notifying 9 NotificationBoard.NotifyLess keyX (value >= threshold): 10.07 >= 10 routine 6 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.08 < 10 : found 10.07 —————> notifying keyX < 10 (9.08) routine 7 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 9.17 < 10 : found 9.08 routine 16 notifying 8 NotificationBoard.NotifyLess keyX (value >= threshold): 10.11 >= 10 routine 10 notifying 9 NotificationBoard.NotifyLess keyX (value < threshold): 9.3 < 10 : found 10.11 —————> notifying keyX < 10 (9.3) routine 29 notifying 8 NotificationBoard.NotifyLess keyX (value < threshold): 9.19 < 10 : found 9.3 routine 18 notifying 8 …

что показывает, что они также находили предыдущие значения из других горутин.

Я почти уверен, что это основная проблема согласования, но я не мог ее обнаружить.

Я использую:

> go version go version go1.10.2 windows/amd64

какие-нибудь идеи?

Есть много кода, который нужно прочитать и понять. Я предлагаю запустить приложение с детектором гонок и отчитаться. Будет полезно знать, работает ли код без гонок или есть гонка, где он расположен.   —  person weeanon    schedule 13.09.2018

Я запустил go test -race для этого пакета, и никакой гонки данных обнаружено не было. тесты только что прошли   —  person weeanon    schedule 13.09.2018

Я не вижу ошибок в вашем выводе … если только я не слепой. Опубликованный вами вывод выглядит как горутины, которые выполняются последовательно. Какой конкретный результат показывает сбой?   —  person weeanon    schedule 13.09.2018

Источник: ledsshop.ru

Стиль жизни - Здоровье!