Задать вопрос
Dunaevlad
@Dunaevlad

Как ускорить работу кода?

Схема работы:

- делаем запрос;
- получаем ответ JSON, парсим его;
- создаем срез с uri адресами(срез содержит до 100 ссылок);
- отправляем в канал другой горутине;
- эта горутина делает запрос ко всем uri(которые находятся в срезе);
- получаем ответ, парсим его;

func Test() {
	chnl := make(chan string)
	wg := new(sync.WaitGroup)
	client := tools.HttpClient()

	wg.Add(1)

	go getSports(chnl, client, wg)
	go getOdds(chnl, client, wg)

	wg.Wait()
}

// Getting live id events and send it to other func-goroutine.
// It sends only data to channel [>> chan<- string].
func getSports(ch chan<- string, client *http.Client, wg *sync.WaitGroup) {
	defer wg.Done()
	// make request
	body := tools.GetRequest(client, "GET", API["sports"])
	// parse json
	var s bet.Sport
	json.Unmarshal(body, &s)

	count := 0
	for _, rawdata := range s {
		// get only necessary events id
		for _, sport := range rawdata.Payload.CompetitionsWithEvents {

			for key := range SportsMap {
				// if sport id not in map
				if sport.Competition.SportID != key {
					continue
				}
				// send event id to  goroutine with chanal
				// this goroutine will make request to get markets
				for _, event := range sport.Events {
					ch <- event.ID
					count++
				}
			}
		}
	}

	fmt.Println()
	fmt.Println("[Total events: ", count, "]")
}

// Getting live events markets.
func getOdds(c <-chan string, client *http.Client, wg *sync.WaitGroup) {
	defer wg.Done()

	for {
		// make request
		uri := fmt.Sprintf(API["odds"] + <-c + ":")
		body := tools.GetRequest(client, "GET", uri)
		// parse json
		var e bet.Event
		json.Unmarshal(body, &e)

		meta := make(map[string]interface{})
		for _, rawdata := range e {
			// make meta info.
			meta["nativeID"] = rawdata.Payload.ID,
		}
		fmt.Println(meta)
	}
}


По факту, у меня две горутины работют синхронно, одна делает запрос, парсит ответ и отправляет по одному евенту в другой канал и тот уже отправляет запрос к uri.
Хотелось бы, что бы код работал паралельно.
Я написал примерный код, но не уверен, что он корретный:

var (
	maxWorkers = runtime.GOMAXPROCS(0)
	sem        = semaphore.NewWeighted(int64(maxWorkers))
	out        = make([]int, 32)
)

// Func getSports is getting live events id.
func getSports(client *http.Client) []string {
	// make request
	body := tools.GetRequest(client, "GET", API["sports"])
	// parse json
	var s Sport
	json.Unmarshal(body, &s)

	// events id will using to make url for requests.
	var uri string
	var events []string
	for _, rawdata := range s {
		for _, sport := range rawdata.Payload.CompetitionsWithEvents {
			// get only necessary events id
			for key := range SportsMap {
				// if sport id not in map
				if sport.Competition.SportID != key {
					continue
				}
				for _, event := range sport.Events {
					uri = fmt.Sprintf(API["odds"] + event.ID + ":")
					events = append(events, uri)
				}
			}
		}
	}
	return events
}

// getOdds is geting live events markets.
func getOdds(client *http.Client, url string, wg *sync.WaitGroup) {
	defer wg.Done()
	defer sem.Release(1)

	body := tools.GetRequest(client, "GET", url)
	MakeMeta(body)
}

// Run scanner.
func Test() {
	ctx := context.Background()
	client := tools.HttpClient()
	wg := new(sync.WaitGroup)

	events := getSports(client)
	for _, url := range events {
		if err := sem.Acquire(ctx, 1); err != nil {
			log.Printf("Failed to acquire semaphore: %v", err)
			break
		}

		wg.Add(1)
		go getOdds(client, url, wg)
	}
	wg.Wait()
	// If you are already waiting for the workers by some other means (such as an
	// errgroup.Group), you can omit this final Acquire call.
	if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil {
		log.Printf("Failed to acquire semaphore: %v", err)
	}

	fmt.Println()
	fmt.Println("[Total events: ", len(events), "]")
}


P.S. если сделать слишком быстрым прогу, сайт-донор присылает пустой массив, думал добавить ограничение горутин)
  • Вопрос задан
  • 173 просмотра
Подписаться 1 Средний 2 комментария
Решения вопроса 1
Для таких целей отлично подходит паттерн "worker pool"
https://gobyexample.com/worker-pools

Создаете воркеров столько, сколько параллельно урлов хотите обрабатывать. Отправляете в канал не слайс урлов, а урлы по-одному. Каждый воркер берет из канала свой урл и все они параллельно обрабатывают разные урлы.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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