Задать вопрос
@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()
}
  • Вопрос задан
  • 839 просмотров
Подписаться 2 Простой Комментировать
Решения вопроса 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
Каналы в го если упрощённо представить то это очереди. Горутины потоки которые воюют за ресурсы и в целом их порядок выполнения можно считать случайно-параллельным в данном примере. Для выведения чисел по порядку в данном случае я бы добавил синхронизирующий примитив на основе мьютекса, который будет следить за очерёдностью использования канала горутинами.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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