Назад
Golang
Горутины vs Потоки: В чём разница?
Если вы давно занимаетесь разработкой, то наверняка слышали про горутины. А потоки - это классика из других языков. Давайте разберёмся, чем они отличаются на простых примерах.
1. Что это?
- Потоки: Это как отдельные вкладки в браузере. Каждый поток - это независимая единица, которая выполняет код. ОС сама решает, когда переключаться между ними. Они используются в языках вроде Java, C++ или Python (с модулем threading).
- Горутины: Это как потоки, но только реализуемые внутри языка Go. Они созданы, чтобы упростить многопоточность. Горутины запускаются ключевым словом
go, и их можно запускать в огромных количествах.
2. Сравнение потребления ресурсов
- Потоки: Каждый поток требует много памяти (обычно 1-8 МБ на стек) и времени на запуск. Если запустить 1000 потоков, система может замедлиться или даже упасть - ОС не любит, когда их слишком много.
- Горутины: Каждая горутина берёт всего 2-4 КБ памяти. Вы можете запустить тысячи или даже миллионы - Go-runtime (внутренняя система Go) справится с этим быстро.
3. Как это работает?
- Потоки: Каждый поток работает отдельно от других. ОС планирует их на процессорные ядра. Переключение между потоками - это как остановить грузовик и запустить другой: медленно и энергозатратно.
- Горутины: Они "мультиплексируются" на меньшее количество реальных потоков. Go-рантайм сам распределяет горутины по потокам (обычно по одному на ядро процессора). Переключение - лёгкое: быстро и без лишних усилий. Если горутина ждёт (например, сетевой запрос), рантайм сразу даёт работу другой.
Пример кода с горутинами
Чтобы наглядно увидеть, вот простой пример на Go. Мы запустим две горутины: одна печатает "Hello", вторая - "World". Они будут работать параллельно.
package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("Hello")
time.Sleep(100 * time.Millisecond) // Задержка, чтобы увидеть параллельность
}
}
func sayWorld() {
for i := 0; i < 5; i++ {
fmt.Println("World")
time.Sleep(100 * time.Millisecond) // Вторая задержка, чтобы увидеть параллельность
}
}
func main() {
go sayHello() // Запускаем горутину для sayHello
go sayWorld() // Запускаем горутину для sayWorld
// Ждём, чтобы горутины завершились (в реальном коде используйте sync.WaitGroup)
time.Sleep(1 * time.Second)
fmt.Println("Done!")
}
Что здесь происходит?
- В
mainмы запускаем две горутины с помощьюgo. Они стартуют параллельно основному потоку. - Каждая печатает слово 5 раз с задержкой.
- Без
time.Sleepв main программа могла бы завершиться раньше. При написании реальной программы используй -sync.WaitGroup.
Если запустишь, увидишь перемешанный вывод: Hello, World, Hello... Это и есть параллельность!
Подведем итоги, горутины лишь эмулируют потоки, но не являются ими технически(в рамках потоков ОС)
Буду рад, если вы поделитесь опытом использования горутин, какие возникали с ними проблемы или сложности. Любая информация, которая поможет предостеречь новичков от огромных проблем🙂