Назад к вопросам
Senior
5
Есть большой файл с миллионом URL-адресов, нужно скачать их быстро, не перегрузив систему и не получив бан от внешнего сервера. Как организовать код?
Компании, где спрашивали
Spectr
Ответ от нейросети
sobes.tech AI
Для быстрой и безопасной загрузки миллиона URL без перегрузки системы и риска бана от сервера нужно:
- Ограничить количество одновременных запросов — использовать пул воркеров или семафор для контроля параллелизма.
- Реализовать rate limiting — ограничить скорость запросов к одному серверу, чтобы не превысить допустимый лимит.
- Обрабатывать ошибки и делать повторные попытки с экспоненциальной задержкой.
- Использовать асинхронные или конкурентные механизмы Go (goroutines + каналы).
Пример на Go с контролем параллелизма и задержками:
package main
import (
"bufio"
"fmt"
"net/http"
"os"
"sync"
"time"
)
func worker(urls <-chan string, wg *sync.WaitGroup, rateLimiter <-chan time.Time) {
defer wg.Done()
client := &http.Client{Timeout: 10 * time.Second}
for url := range urls {
<-rateLimiter // ждем разрешения на запрос
resp, err := client.Get(url)
if err != nil {
fmt.Printf("Ошибка при загрузке %s: %v\n", url, err)
continue
}
resp.Body.Close()
fmt.Printf("Загружено: %s\n", url)
}
}
func main() {
file, err := os.Open("urls.txt")
if err != nil {
panic(err)
}
defer file.Close()
urls := make(chan string, 100)
var wg sync.WaitGroup
// Ограничение скорости: 10 запросов в секунду
rateLimiter := time.Tick(100 * time.Millisecond)
// Запускаем 20 воркеров
for i := 0; i < 20; i++ {
wg.Add(1)
go worker(urls, &wg, rateLimiter)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
urls <- scanner.Text()
}
close(urls)
wg.Wait()
}
В этом примере:
- 20 параллельных воркеров обрабатывают URL.
rateLimiterограничивает скорость запросов до 10 в секунду.- Используется таймаут HTTP клиента.
Такой подход позволяет эффективно загружать много URL, не перегружая систему и не вызывая блокировки со стороны сервера.