Каким образом можно распараллелить выполнение кода в Go, и какие средства параллельных вычислений доступны?

Пользователь

от kole_will , в категории: Вопросы от знатоков , год назад

Каким образом можно распараллелить выполнение кода в Go, и какие средства параллельных вычислений доступны?

Facebook Vk Ok Twitter LinkedIn Telegram Whatsapp Pocket

1 ответ

Пользователь

от marjorie.goldner , год назад

@kole_will 

В Go существует несколько способов распараллеливания выполнения кода:

  1. Go рутины (goroutines): Go рутина - это легковесный поток выполнения, который создается и управляется с помощью Go среды выполнения. Для создания Go рутины достаточно использовать ключевое слово go перед вызовом функции.


Пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func main() {
    go func1()
    go func2()
    // ...
    time.Sleep(time.Second) // Ожидание завершения всех Go рутин
}

func func1() {
    // Код функции func1
}

func func2() {
    // Код функции func2
}


  1. Каналы (channels): Каналы в Go служат для обмена данными между Go рутинами. Каналы, в отличие от переменных, являются безопасными для параллельного доступа и предоставляют средства синхронизации выполнения кода.


Пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func1(ch1)
    go func2(ch2)

    result1 := <-ch1 // Получение данных из канала ch1
    result2 := <-ch2 // Получение данных из канала ch2

    // Использование результатов
}

func func1(ch chan int) {
    // Код функции func1
    ch <- result1 // Помещение результата в канал ch
}

func func2(ch chan int) {
    // Код функции func2
    ch <- result2 // Помещение результата в канал ch
}


  1. WaitGroup (счетчик ожидания): WaitGroup предоставляет возможность ожидать завершения выполнения определенного количества Go рутин.


Пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    var wg sync.WaitGroup

    wg.Add(2) // Устанавливаем счетчик ожидания на 2

    go func1(&wg)
    go func2(&wg)

    wg.Wait() // Ожидание завершения всех Go рутин
}

func func1(wg *sync.WaitGroup) {
    // Код функции func1
    wg.Done() // Уменьшение счетчика ожидания на 1
}

func func2(wg *sync.WaitGroup) {
    // Код функции func2
    wg.Done() // Уменьшение счетчика ожидания на 1
}


  1. Mutex (взаимное исключение): Mutex может использоваться для синхронизации доступа к общим данным из нескольких Go рутин.


Пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var mutex sync.Mutex
var counter int

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }

    wg.Wait() // Ожидание завершения всех Go рутин

    fmt.Println(counter)
}

func increment(wg *sync.WaitGroup) {
    mutex.Lock() // Блокировка доступа к общим данным
    counter++
    mutex.Unlock() // Разблокировка доступа к общим данным

    wg.Done()
}


Это лишь некоторые возможности параллельных вычислений в Go. Всего лишь за ними следуют Go-средства для работы с параллельными вычислениями, такие как пулы горутин (goroutine pool), пулы задач (task pools), паттерны проектирования вроде потоковых каналов (streaming channels) и другие.