VGrabko
@VGrabko
Golang, Php, Js

Как выйти из main после завершения всех рутин?

У меня есть некая рутина которая запускает 10500 других рутин. main слушает канал. Но когда рутины уменрли main то не умирает.
  • Вопрос задан
  • 1607 просмотров
Решения вопроса 2
@FireGM
https://golang.org/pkg/sync/#example_WaitGroup
Хотя с каналами и быстрее, но я предпочитаю контроль через wg.

upd.

Контролируйте количество рутин. Раздробите приложение на маленькие функции.
в главном сразу запускается 10 рутин на выполнение запросов, 10 рутин на анализ ответа от сторонего сервиса, 10 рутин ещё чего-либо.
Рутины для выполнения запросов принимают, например, из единого канала урл, на который надо сделать запрос. Отправляете урл в канал, свободная рутина хватает и выполняет запрос, получет ответ, передает в другой канал, из которого уже хватает свободная рутина для анализа ответа. Ну и т.д.

Вот топорный пример, как делаю я

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	urls := []string{"http://google.ru", "http://vk.com", "http://ya.ru"}
	chanUrls := make(chan string, 100)
	chanRes := make(chan http.Response, 100)
	chanPrint := make(chan string, 100)
	for _, url := range urls {
		chanUrls <- url
	}
	close(chanUrls)
	go httpGet(chanUrls, chanRes)
	go analys(chanRes, chanPrint)
	printRes(chanPrint)
}

func httpGet(chanUrls <-chan string, chanRes chan<- http.Response) {
	defer close(chanRes)
	for url := range chanUrls {
		res, err := http.DefaultClient.Get(url)
		if err == nil {
			chanRes <- *res
		}
	}
}

func analys(chanRes <-chan http.Response, chanPrint chan<- string) {
	defer close(chanPrint)
	for res := range chanRes {
		body, err := ioutil.ReadAll(res.Body)
		if err == nil {
			chanPrint <- string(body)
		}
	}
}

func printRes(chanPrint <-chan string) {
	for pr := range chanPrint {
		fmt.Println(pr)
	}
}
Ответ написан
Комментировать
@arctblake
В main:
var wg sync.WaitGroup
...
Перед запуском каждой горутины сделать wg.Add(1) (не в самих горутинах, а в том же main прямо перед go ...

В каждую горутину первой строчкой добавить defer func() { wg.Done() }()

Потом в main создать еще одну горутину - контролирующую. В ней всего 2 строчки:
wg.Wait()
close(канал)

Ну и дальше в main остальной код.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@cijiw
Канал то нужно или закрыть или записать что-нибудь в него.
Ответ написан
taliban
@taliban
php программист
Не все умерли значит, го вообще не ждет рутины, он ждет каналы, если майн не выходит, значит не все рутины сообщили об окончании в канал.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы