Мы рассмотрим несколько примеров запуска goroutine и контроля их выполнения.
В golang есть отличный механизм для запуска параллельных потоков например:
package main
import (
"log"
"time"
)
func job(duration time.Duration) {
<-time.After(duration)
log.Println("job done")
}
func main() {
go func(){
job(time.Minute)
}()
}
Но как и любой механизм он не лишен недостатков, предыдущий пример может не завершить работу в goroutine при этом основной поток уже будет остановлен.
Нам уже необходимо будет ожидать выполнение процесса например при помощи `WaitGroup`
package main
import (
"log"
"sync"
"time"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
job(time.Microsecond)
}()
wg.Wait()
}
А что если нам надо чтобы процесс был запущен много раз, тогда получается
package main
import (
"log"
"time"
)
func main() {
go func() {
for{
job(time.Minute)
}
}()
}
В примерах я буду показывать только ключевые моменты, посмотреть пример полностью можно будет в Go Playground по ссылке.
Данный пример будет работать пока мы не завершим процесс принудительно. Но что если работу нужно завершить а только потом можно завершать весь процесс, это можно сделать например
package main
import (
"context"
"log"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(),time.Microsecond)
defer cancel()
go func() {
for{
select{
case <-ctx.Done():
return
default:
job(time.Microsecond/2)
}
}
}()
}
В этом случае мы управляем процессом с помощью пакета `context`, он может быть остановлен к примеру `graceful shutdown` но об этом в следующий раз.
Эта работа будет запускаться всегда как только завершится предыдущая, это встречается редко, обычно нам надо запускать обработку не чаще чем, изменим код и получится
package main
import (
"context"
"log"
"time"
)
func main() {
go func() {
for{
select{
case <-time.After(time.Microsecond):
job(time.Microsecond/2)
}
}
}()
}
Выводы
Я привел несколько примеров как просто запускать выполнение фоновых операций параллельно, но это не все что может потребоваться. Обычно это вырастает в каждом проекте по своему, ведь это просто, потом разрастается ведь нам к примеру нужны будут еще метрики и запись логов, ведь процесс фоновый. Чтобы избежать повторения базового решения можно использовать пакет go-4devs/daemon, который уже все это делает и даже больше. Включая обработку завершения работ(jobs), завершения всех запущенных job и тп.