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

Создание Go-процедур

Создать go-рутину очень просто, все, что вам нужно сделать, это использовать ключевое слово «go», за которым следует вызов функции. Вот пример:

package main

import "fmt"

func printHello() {
    fmt.Println("Hello from go-routine!")
}

func main() {
    go printHello()
    fmt.Println("Hello from main!")
}

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

Параллельное выполнение

Одним из основных преимуществ go-routines является возможность легкого одновременного выполнения задач. Например, программа может запускать несколько подпрограмм для параллельного выполнения сетевых запросов, повышая общую производительность программы. Вот пример программы, которая одновременно извлекает содержимое двух веб-страниц:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func fetchWebPage(url string) {
    resp, err := http.Get(url)
    if err != nil {
        fmt.Printf("Error fetching %s: %s\n", url, err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading %s: %s\n", url, err)
        return
    }
    fmt.Printf("%s: %d bytes\n", url, len(body))
}

func main() {
    go fetchWebPage("https://www.example.com")
    go fetchWebPage("https://www.example2.com")
    fmt.Println("Fetching web pages...")
}

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

Синхронизация

Еще одним преимуществом go-процедур является возможность легко управлять и синхронизировать их выполнение. Go предоставляет встроенный механизм, называемый каналами, который позволяет go-процедурам общаться и синхронизироваться друг с другом. Каналы можно использовать для отправки и получения данных между go-процедурами, а также для реализации расширенных шаблонов синхронизации, таких как конвейеры и разветвления входа/выхода.

Вот пример конвейера, который выполняет ряд задач:

package main

import "fmt"

func task1(in chan int, out chan int) {
    for i := range in {
        out <- i * 2
    }
    close(out)
}

func task2(in chan int, out chan int) {
    for i := range in {
      out <- i + 1
      }
  close(out)
}

func main() {
  input := make(chan int)
  output := make(chan int)

  go task1(input, output)
  go task2(output, input)

  for i := 0; i < 10; i++ {
    input <- i
  }
  close(input)

  for result := range input {
    fmt.Println(result)
  }
}

В этом примере у нас есть две задачи, «задача1» и «задача2», которые связаны через каналы. `task1` берет входной канал, умножает каждое входящее значение на 2 и отправляет его в выходной канал. `task2` принимает вывод `task1`, добавляет 1 к каждому входящему значению и отправляет его во входной канал. Это создает конвейер, в котором выходные данные «задачи 1» становятся входными данными «задачи 2» и так далее. В основной функции мы запускаем обе задачи как go-процедуры, а затем отправляем 10 значений на входной канал. Результаты считываются из входного канала и выводятся на консоль.

Заключение

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

Еще 🤔

Являются ли подпрограммы Go многопоточными?

С Go можно выполнять многопоточный параллелизм, а распараллеливание с горутинами и горутинами работает асинхронно, что позволяет эффективно использовать как многопоточность, так и асинхронное программирование.