@Kairr

Как синхронизировать горутины?

Я только начинаю разбираться с Go.
Подскажите плиз в какую сторону можно подумать?
Мне нужно чтобы цифры выводились по порядку. Этот код вроде как работает, но иногда выводит цифры вразброс

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	num := make(chan string)


	go func() {
		for _, value := range []int{1, 3, 5} {
			num <- "ok"
			fmt.Println(value)
		}
		wg.Done()
	}()

	go func() {
		for _, value := range []int{2, 4, 6} {
			<- num
			fmt.Println(value)
		}
		wg.Done()
	}()

	wg.Wait()
}
  • Вопрос задан
  • 615 просмотров
Решения вопроса 1
EvgenyMamonov
@EvgenyMamonov Куратор тега Go
Senior software developer, system architect
Горутины синхронизировать/обмениваться данными можно при помощи каналов.
У вас не очень удачный пример для обучения.
Обычно есть горутина или несколько, которые получают данные и пишут их в канал и есть горутина или несколько, которые будут читать из канала.
Читающие горутины будут получать данные из канала в той последовательности, в которой они туда попали.
Ближе к реальности пример будет выглядеть вот так.
Одна горутина пишет данные в канал, а две горутины по очереди извлекают данные.
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    num := make(chan int, 1000) // 1000 - размер буффера канала

    wg.Add(1)
    go func() {
        for i := 0; i < 1000; i++ {
            num <- i
            fmt.Printf("write to channel: %d\n", i)
            // задержка нужна только на время теста
            time.Sleep(100 * time.Microsecond)
        }
        close(num)
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        for {
            val, ok := <-num
            if !ok {
                break
            }
            fmt.Printf("goroutine 1 got: %d\n", val)
        }
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        for {
            val, ok := <-num
            if !ok {
                break
            }
            fmt.Printf("goroutine 2 got: %d\n", val)
        }
        wg.Done()
    }()

    wg.Wait()
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@Kenit
Каналы в го если упрощённо представить то это очереди. Горутины потоки которые воюют за ресурсы и в целом их порядок выполнения можно считать случайно-параллельным в данном примере. Для выведения чисел по порядку в данном случае я бы добавил синхронизирующий примитив на основе мьютекса, который будет следить за очерёдностью использования канала горутинами.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы