Горутины
Введение в конкурентность Go — ключевое слово go, чем горутина «легче» потока ОС и ожидание группы горутин через sync.WaitGroup.
2 вопросов
JuniorТеорияЧастоЧто делает ключевое слово go в Go?
Что делает ключевое слово go в Go?
go f() запускает горутину — лёгкую конкурентную функцию, планируемую средой выполнения. Вызов возвращается немедленно, и f выполняется независимо от вызывающего, поэтому оба идут одновременно. Горутины мультиплексируются на потоки ОС средой выполнения Go, поэтому можно дёшево запускать тысячи. Когда func main возвращается, программа завершается и все ещё работающие горутины останавливаются, поэтому нужно явно координировать ожидание их завершения.
Типичные ошибки
- ✗Думать, что
go f()блокирует вызывающего, покаfне вернётся - ✗Считать, что каждая горутина стоит целого потока ОС
- ✗Забывать, что горутины умирают при возврате
func main
Уточняющие вопросы
- →Как заставить
mainдождаться завершения горутины? - →Почему горутины дешевле потоков ОС?
JuniorТеорияЧастоЧто такое sync.WaitGroup и каков контракт Add/Done/Wait?
Что такое sync.WaitGroup и каков контракт Add/Done/Wait?
sync.WaitGroup ждёт завершения набора горутин. Он хранит счётчик: вызовите Add(n) перед запуском горутин, чтобы поднять его, вызовите Done() (обычно через defer) внутри каждой горутины, чтобы уменьшить на единицу, и вызовите Wait(), чтобы заблокироваться, пока счётчик не дойдёт до нуля. Ключевое правило — вызывать Add в запускающей горутине до оператора go, а не внутри новой горутины, иначе Wait может вернуться слишком рано.
Типичные ошибки
- ✗Вызывать
Addвнутри горутины вместо как доgo - ✗Забывать
defer wg.Done(), из-за чего счётчик не падает - ✗Копировать
WaitGroupпо значению вместо передачи указателя
Уточняющие вопросы
- →Что произойдёт, если
Doneвызвать чаще, чемAdd? - →Чем
WaitGroupотличается от ожидания на каналеdone?