Горутины

Board index Программирование GoLand

Description: Программирование на языке Go

#1by mexan » 02.01.2025, 21:03

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

Горутины обладают фиксированным начальным размером стека (обычно около 2 КБ), что позволяет создавать тысячи горутин без значительного потребления памяти. Это выгодно отличается от традиционных потоков, которые требуют значительно большего объема памяти для запуска.

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

При создании новой горутины ей выделяется минимальный объем памяти. Однако, если задача требует большего стека (например, при глубокой рекурсии), система автоматически расширяет его:
  • Начальный размер: Новая горутина получает стек фиксированного размера (примерно 2 КБ).
  • Расширение стека: Если горутина исчерпывает выделенный объем памяти, система создает новый блок памяти большего размера.
  • Копирование данных: Все данные со старого стека копируются на новый.
  • Продолжение выполнения: Горутина переключается на новый стек и продолжает выполнение.
Этот процесс минимально влияет на производительность и прозрачен для разработчика.

Выполнение горутин управляется встроенным планировщиком Go. Он распределяет горутины по потокам системы, определяя порядок их выполнения. Планировщик работает асинхронно, что делает порядок завершения горутин непредсказуемым.

Для синхронизации выполнения горутин и предотвращения преждевременного завершения программы используется механизм sync.WaitGroup. Этот инструмент позволяет основной горутине ожидать завершения всех дочерних задач перед завершением программы:
Code: Select all
package main

import (
   "fmt"
   "sync"
)

func worker(id int, wg *sync.WaitGroup) {
   defer wg.Done() // Уменьшаем счетчик по завершении горутины
   fmt.Printf("Worker %d started\n", id)
   // Здесь выполняется какая-то работа
   fmt.Printf("Worker %d finished\n", id)
}

func main() {
   var wg sync.WaitGroup
   for i := 1; i <= 5; i++ {
      wg.Add(1) // Увеличиваем счетчик перед запуском новой горутины
      go worker(i, &wg)
   }
   wg.Wait() // Ожидаем завершения всех горутин
   fmt.Println("All workers finished")
}

Основная горутина создается автоматически при запуске программы. Если основная горутина завершает выполнение (например, достигает конца функции main()), программа завершается, даже если другие горутины все еще работают. Чтобы избежать этого, используйте механизмы синхронизации, такие как sync.WaitGroup.
mexan
Администратор
Reputation: 0
Posts: 179
Topics: 138

#2by mexan » 02.01.2025, 22:32

Что такое: var wg sync.WaitGroup?
Это структура в пакете sync, используемая для ожидания завершения группы горутин. Она позволяет отслеживать, сколько горутин запущено, и блокирует выполнение программы до тех пор, пока все горутины не завершат свою работу.

Когда её использовать?
WaitGroup используется, когда вы запускаете несколько горутин одновременно и хотите дождаться их завершения, прежде чем продолжить выполнение основной программы или завершить её. Это особенно полезно в параллельных вычислениях, где вам нужно убедиться, что все задачи завершены, прежде чем продолжить.

Основные методы WaitGroup:
  1. Add(n int)[/icode]: Увеличивает счётчик на заданное значение [tt]n. Обычно вызывается до запуска горутины, чтобы указать, сколько горутин будет запущено.
  2. Done(): Уменьшает счётчик на 1, когда горутина завершается. Это должен вызывать код, выполняемый в горутине.
  3. Wait(): Блокирует выполнение текущей горутины (например, основной горутины) до тех пор, пока счётчик не станет равным нулю. Это означает, что все горутины завершили свою работу.
mexan
Администратор
Reputation: 0
Posts: 179
Topics: 138

#3by mexan » 02.01.2025, 22:35

Еще пример:
Code: Select all
package main

import (
   "fmt"
   "sync"
)

var wg sync.WaitGroup

func main() {
   for i := 0; i < 5; i++ {
      wg.Add(1)
      go greeting()
   }
   wg.Wait()
}

func greeting() {
   fmt.Println("Hello World!!!")
   wg.Done()
}

Запускается функция main(), которая выполняет основной код программы.
В цикле for i := 0; i < 5; i++ мы запускаем 5 горутин:
  • wg.Add(1) увеличивает счетчик wg на 1, что указывает, что мы ожидаем завершения одной новой горутины.
  • go greeting() запускает новую горутину, которая вызовет функцию greeting.
  • После запуска всех горутин вызывается wg.Wait(), который блокирует выполнение главной горутины до тех пор, пока счетчик wg не станет равным нулю (что означает, что все горутины завершили свою работу).

Функция greeting() выводит "Hello World!!!" в консоль.
  • wg.Done() уменьшает счетчик wg на 1, сигнализируя, что текущая горутина завершилась. Это необходимо для правильной работы wg.Wait() в функции main.
mexan
Администратор
Reputation: 0
Posts: 179
Topics: 138


Return to GoLand

cron