Основы горутин
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 59 из 107.
goroutine — это лёгкий поток выполнения, управляемый средой выполнения Go. В отличие от традиционных потоков, которые потребляют значительный объём памяти, goroutines начинают работу всего с несколькими килобайтами места в стеке, что позволяет запускать тысячи из них concurrently.
Чтобы запустить goroutine, просто поместите ключевое слово go перед вызовом функции:
func sayHello(name string) {
fmt.Println("Hello,", name)
}
func main() {
go sayHello("Alice") // выполняется параллельно
go sayHello("Bob") // выполняется параллельно
time.Sleep(100 * time.Millisecond)
fmt.Println("Done")
}Когда выполняется go sayHello("Alice"), программа не ждёт завершения sayHello. Вместо этого она сразу переходит к следующей строке, пока sayHello выполняется в фоновом режиме. Поэтому нам нужен time.Sleep: без него main завершилась бы до того, как goroutines завершат работу.
Вы также можете запускать goroutines с помощью анонимных функций:
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")Сама main function выполняется в goroutine. Когда она возвращается, все остальные goroutines немедленно завершаются. У них нет возможности завершить работу. Использование time.Sleep — это временное решение; в следующих уроках ты изучишь правильные методы синхронизации с помощью каналов и групп ожидания.
Задание
ЛегкоДавайте создадим средство запуска задач, которое выполняет несколько задач concurrently с помощью goroutines. Вы создадите простую систему, в которой задачи выполняются в фоновом режиме, пока основная программа продолжает работу, демонстрируя, как goroutines обеспечивают параллельное выполнение.
Вы организуете код в двух файлах:
tasks.go: Define логику выполнения задач.Создайте структуру
Taskс полямиName(string) иDuration(int, representing миллисекунды).Implement method
Run()дляTask, который имитирует работу, приостанавливая выполнение на duration задачи, а затем выводит:Task [Name] completedСоздайте function
RunAllTasks(tasks []Task), которая запускает methodRun()каждой задачи как goroutine. После запуска всех goroutines она должна приостановить выполнение на 500 milliseconds, чтобы позволить им завершиться, а затем вывести:All tasks launchedmain.go: Считайте информацию о задачах и организуйте concurrent выполнение.Считайте number задач, затем считайте name и duration каждой задачи. Создайте задачи и передайте их в
RunAllTasks. После её возврата выведите:Main function done
Будут предоставлены следующие входные данные:
- Line 1: Number of tasks (integer)
- Следующие lines: для каждой задачи — две строки: name задачи, затем её duration в milliseconds
Например, если дано:
3
Download
100
Process
50
Upload
75Ваша output должна показывать завершение задач (порядок может различаться из-за concurrency), за которым следуют сообщения о завершении:
Task Process completed
Task Upload completed
Task Download completed
All tasks launched
Main function doneПримечание: поскольку goroutines выполняются concurrently, задачи с меньшей duration обычно завершаются первыми. Порядок завершения задач зависит от их durations — более короткие задачи завершаются раньше более длительных.
Используйте time.Sleep вместе с time.Duration и time.Millisecond для задержек. Помните, что без sleep в RunAllTasks function вернула бы управление до того, как goroutines завершат свою работу.
Попробуйте сами
package main
import (
"fmt"
)
func main() {
// Прочитать количество задач
var numTasks int
fmt.Scanln(&numTasks)
// TODO: Создать слайс для хранения задач
// TODO: Прочитать имя и длительность каждой задачи
// Для каждой задачи:
// - Прочитать имя задачи
// - Прочитать длительность (как целое число)
// - Создать Task и добавить в ваш слайс
// TODO: Вызвать RunAllTasks с вашим слайсом задач
// TODO: Print "Main function done"
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker PoolПотренируйтесь самостоятельно: Онлайн-компилятор Go