Параллелизм — одна из основных функций языка программирования Go. Go предоставляет мощную и простую в использовании модель параллелизма, которая позволяет разработчикам писать высокопроизводительные и масштабируемые программы. В этой статье мы рассмотрим основы параллелизма в Go и научимся писать параллельные программы.

Что такое параллелизм?

Параллелизм — это способность программы выполнять несколько задач одновременно. В параллельной программе разные части программы могут выполняться независимо друг от друга. Это может привести к повышению производительности и масштабируемости, поскольку программа может лучше использовать доступные ресурсы.

В Go параллелизм достигается с помощью горутин и каналов.

Горутины

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

Вот пример того, как создать горутину в Go:

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello, World!")
}

func main() {
    go sayHello() // create a new goroutine
    time.Sleep(time.Second) // wait for a second
}

Вывод:

Hello, World!

В этом примере мы определили функцию с именем sayHello, которая просто печатает «Hello, World!» к консоли. Затем мы создаем новую горутину, вызывая эту функцию с ключевым словом go. Это выполнит функцию sayHello одновременно с основной программой.

Поскольку основная программа завершится до завершения горутины, мы используем функцию time.Sleep, чтобы приостановить основную программу на одну секунду, чтобы дать горутине время для завершения. Без этой задержки программа завершилась бы до того, как sayHello функция смогла завершить выполнение.

Когда мы запустим эту программу, мы увидим вывод «Hello, World!» выводится на консоль, демонстрируя, что горутина была успешно создана и выполнена одновременно с основной программой.

Вот пример использования параллелизма и горутин в Go для одновременного выполнения некоторых задач:

package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 10; i++ {
        time.Sleep(500 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}

func printLetters() {
    for i := 'a'; i <= 'j'; i++ {
        time.Sleep(300 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}

func main() {
    go printNumbers()
    go printLetters()

    time.Sleep(5 * time.Second)
    fmt.Println("Done")
}

В этом примере мы определили две функции printNumbers и printLetters, каждая из которых печатает последовательность цифр и букв соответственно с небольшой задержкой между каждым выводом.

Затем мы создаем две горутины, вызывая эти функции с ключевым словом go. Это выполнит обе функции одновременно с основной программой.

Чтобы обеспечить выполнение обеих горутин, мы используем функцию time.Sleep, чтобы приостановить основную программу на 5 секунд, прежде чем вывести на консоль сообщение «Готово».

Когда мы запустим эту программу, мы увидим, что числа и буквы печатаются чередующимися друг с другом, демонстрируя, что две горутины выполняются одновременно:

Вывод:

#SampleOutput1
a 1 b c 2 d e 3 f 4 g h 5 i j 6 7 8 9 10 Done
#SampleOutput2
a 1 b c 2 d 3 e f 4 g h 5 i 6 j 7 8 9 10 Done

Репозиторий кода:https://github.com/SidharthSasikumar/golang/tree/main/102-Goroutines

Каналы

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

Для создания канала мы используем функцию make и указываем тип значений, которые будет обрабатывать канал. Например:

ch := make(chan int)

В этом примере мы создаем новый канал, который может обрабатывать значения типа int.

Мы можем отправить значение в канал с помощью оператора <-. Например:

ch <- 42

В этом примере мы отправляем значение 42 в канал ch.

Мы также можем получить значение из канала с помощью оператора <-. Например:

x := <-ch

В этом примере мы получаем значение из канала ch и сохраняем его в переменной x.

Пример канала в golang: https://github.com/SidharthSasikumar/golang/tree/main/103-GoChannel

Объединение горутин и каналов

Комбинируя горутины и каналы, мы можем создавать высококонкурентные программы, которые легко анализировать и отлаживать.

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

package main

import (
 "fmt"
)

func main() {
 ch := make(chan int)

 go func() {
  ch <- calculateSum(1, 2)
 }()

 go func() {
  ch <- calculateSum(3, 4)
 }()

 sum := <-ch + <-ch
 fmt.Println(sum) // Output: 10
}

func calculateSum(x, y int) int {
 return x + y
}

Вывод:

10

В этом примере мы создаем две горутины, которые одновременно вычисляют сумму двух чисел. Мы используем каналы для передачи результатов вычислений обратно в основную программу. Наконец, мы складываем два результата вместе и выводим сумму на консоль.

Другие примеры Go Rouniten и каналов см. по адресу: https://github.com/SidharthSasikumar/golang/tree/main/104-GoProducerConsumer

Заключение

Параллелизм — важная особенность современных языков программирования, и Go предоставляет мощную и простую в использовании модель параллелизма. Используя горутины и каналы, мы можем писать высококонкурентные программы, которые эффективны и просты в понимании. Мы рекомендуем вам изучить многие функции модели параллелизма Go и поэкспериментировать с написанием собственных параллельных программ. Удачного кодирования!