Задать вопрос

Лучший способ избежать race condition, в данном случае?

Здравствуйте.

Есть сервис, который обрабатывает некоторый поток данных пулом воркеров.

Вот упрощенный, в целях демонстрации, код:

spoiler
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

var (
	maxWorkers = 5

	pool    = make(chan struct{}, maxWorkers)
	input   = make(chan int, 0)
	results = make([]int, 0)
)

func main() {
	go func() {
		defer close(input)

		// какой-то рандомный input
		rand.Seed(time.Now().Unix())
		limit := rand.Intn(40) + 1

		for i := 0; i < limit; i++ {
			input <- i
		}
	}()

	var wg sync.WaitGroup

	// главный процесс пула воркеров
	for i := range input {
		pool <- struct{}{}
		wg.Add(1)

		go func(i int) {
			defer func() {
				wg.Done()
				<-pool
			}()

			// здесь race condition
			results = append(results, pow(i+1, 2))
		}(i)
	}

	wg.Wait()

	fmt.Println(results)
}

func pow(n int, power int) int {
	fmt.Println("worker started")
	time.Sleep(time.Second * 2)

	return n * power
}


Как в этом случае избежать race condition? Mutex здесь не поможет, так как он будет блокировать всех воркеров, и они будут выполняться по очереди.
Из вариантов: использовать дополнительный канал.
Но может есть более удобный способ?
  • Вопрос задан
  • 340 просмотров
Подписаться 3 Простой 1 комментарий
Решения вопроса 1
@ghostiam
На Go писатель, серверов пинатель.
Примеры с каналом
Когда знаем кол-во данных:
https://play.golang.org/p/7pNGCebvqlo
Когда не знаем:
https://play.golang.org/p/7WtVnXwjtuo

Подробности в комментариях:
https://qna.habr.com/answer?answer_id=1901263#comm...
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@raiboon
Два варианта.
1. Мьютекс. С чего вы взяли, что воркеры будут выполняться по очереди? Сначала идет какая-то долгая работа конкурентно, а потом мьютекс на короткий промежуток времени закрывает слайс, пока идет в него добавление результата.
2. Канал. Смысл в том, что результаты собираются в одной горутине. Тогда не будет конкурентной записи в слайс. Это более go way. Это можно делать в main или запустить еще одну.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы