@dcaraxes
meme engineer

Как быстро отправить 1 миллион запросов на внешний API?

Добрый день! Задача такая - с помощью внешнего сервиса нужно сравнить одно константное значение с миллионом других значений, которые берутся из CSV-таблицы. Каким образом лучше всего спроектировать приложение, чтобы быстрее отправлял один миллион запросов и обрабатывал их? С примером кода будет хорошо, но буду рад любой подсказке. Спасибо!
  • Вопрос задан
  • 313 просмотров
Пригласить эксперта
Ответы на вопрос 3
@falconandy
Навскидку придумался какой-то такой алгоритм, возможно некорректный:
0. преполагается видимо, что константная точка неизвестна, а сервис возвращает расстояние от неё до переданной точки
1. берете две произвольные (но разные) точки P1, P2 из своего миллиона и отправляете два запроса, получая два расстояния R1, R2
2. неизвестная константная точка находится в точках пересечения двух окружностей с центрами P1, P2 и радиусами R1, R2
3. по идее таких пересечений будет два, возможно одно, если повезет
4. если одно, то оно и будет той самой неизвестной константной точкой
5. если два, то отправляете каждую на сервис и проверяете, до какой расстояние будет нулевое - это и будет та самая неизвестная константная точка
6. локально находите ближайшую к теперь уже известной константной точке из своего миллиона

В результате, максимум 4 запроса к сервису.
Не забываем про погрешности при работе с числами.
Ответ написан
gogowq
@gogowq
Ozh domosh acha ozh
Go с использованием горутин (goroutines) и каналов (channels):
package main

import (
	"encoding/csv"
	"fmt"
	"net/http"
	"os"
	"sync"
)

const (
	apiURL      = "https://api.example.com/compare" // Замените на реальный URL API
	concurrency = 100                                // Количество одновременных запросов
)

func main() {
	// Чтение значений из CSV-файла
	values, err := readCSV("data.csv") // Замените "data.csv" на путь к вашему CSV-файлу
	if err != nil {
		fmt.Println("Ошибка чтения CSV:", err)
		return
	}

	var wg sync.WaitGroup
	semaphore := make(chan struct{}, concurrency)

	for _, value := range values {
		wg.Add(1)
		go func(v string) {
			semaphore <- struct{}{} // Блокировка до доступности слота в семафоре
			defer func() {
				<-semaphore // Освобождение слота в семафоре
				wg.Done()
			}()

			err := makeAPIRequest(v)
			if err != nil {
				fmt.Printf("Ошибка запроса для значения %s: %s\n", v, err)
			}
		}(value)
	}

	wg.Wait()
	fmt.Println("Все запросы выполнены.")
}

func readCSV(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	reader := csv.NewReader(file)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	var values []string
	for _, record := range records {
		values = append(values, record[0]) // Предполагается, что значения находятся в первом столбце CSV
	}

	return values, nil
}

func makeAPIRequest(value string) error {
	// Создание HTTP-запроса к внешнему API
	req, err := http.NewRequest(http.MethodGet, apiURL, nil)
	if err != nil {
		return err
	}

	// Добавление параметров запроса
	q := req.URL.Query()
	q.Add("value", value) // Замените на реальные параметры запроса
	req.URL.RawQuery = q.Encode()

	// Отправка запроса
	client := http.Client{}
	_, err = client.Do(req)
	if err != nil {
		return err
	}

	return nil
}
Ответ написан
@d-stream
Готовые решения - не подаю, но...
Думаю начать стоит с рефакторинга смыла действия. Например одним запросом отправить сервису заархивированную .csv таблицу и в ответ получить результат сравнения в виде таблицы номеров строк где есть совпадение.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы