Найти в Дзене

Golang с нуля: Горутины и каналы — магия параллелизма

(Статья 4 из цикла "Golang с нуля") Одна из визитных карточек Go — это его мощная и при этом простая модель параллелизма, основанная на горутинах и каналах. В этой статье мы погрузимся в эту тему и посмотрим, как легко писать конкурентный код на Go. Горутина (goroutine) — это легковесная, независимая функция, которая может выполняться одновременно с другими горутинами. В отличие от традиционных потоков операционной системы, создание и переключение между горутинами происходит гораздо быстрее и с меньшими затратами ресурсов. Чтобы запустить функцию как горутину, достаточно добавить ключевое слово go перед её вызовом:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond) // Имитируем работу
fmt.Println(s)
}
}
func main() {
go say("Привет")
go say("Мир")
time.Sleep(2 * time.Second) // Ждём, пока обе горутины закончат
}
В этом примере две функции say запускаются параллельно. Без time.Sleep в main программа заве
Оглавление

(Статья 4 из цикла "Golang с нуля")

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

🔹 Что такое горутины?

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

Чтобы запустить функцию как горутину, достаточно добавить ключевое слово go перед её вызовом:

package main

import (
"fmt"
"time"
)

func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond) // Имитируем работу
fmt.Println(s)
}
}

func main() {
go say("Привет")
go say("Мир")

time.Sleep(2 * time.Second) // Ждём, пока обе горутины закончат
}

В этом примере две функции say запускаются параллельно. Без time.Sleep в main программа завершилась бы сразу, не дождавшись выполнения горутин. Это показывает, что горутины работают асинхронно, и основная программа не ждёт их завершения.

🔹 Что такое каналы?

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

Философия Go: "Не общайтесь, разделяя память; делитесь памятью, общаясь." (Don't communicate by sharing memory, share memory by communicating.)

Пример использования каналов:

package main

import "fmt"

func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // Отправляем сумму в канал c

}

func main() {
s := []int{7, 2, 8, -9, 4, 0}

c := make(chan int) // Создаём канал для обмена данными
go sum(s[:len(s)/2], c) // Запускаем горутину для первой половины слайса
go sum(s[len(s)/2:], c) // Запускаем горутину для второй половины

x, y := <-c, <-c // Получаем значения из канала

fmt.Println("Сумма первой части:", x)
fmt.Println("Сумма второй части:", y)
fmt.Println("Общая сумма:", x+y)

}

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

💡 Вывод

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

Что дальше?

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

Попробуйте написать свою программу с использованием горутин и каналов. Поделитесь идеями в комментариях!