Sobes.tech
Назад к вопросам
Senior
5

Есть большой файл с миллионом URL-адресов, нужно скачать их быстро, не перегрузив систему и не получив бан от внешнего сервера. Как организовать код?

Компании, где спрашивали
Spectr

Ответ от нейросети

sobes.tech AI

Для быстрой и безопасной загрузки миллиона URL без перегрузки системы и риска бана от сервера нужно:

  1. Ограничить количество одновременных запросов — использовать пул воркеров или семафор для контроля параллелизма.
  2. Реализовать rate limiting — ограничить скорость запросов к одному серверу, чтобы не превысить допустимый лимит.
  3. Обрабатывать ошибки и делать повторные попытки с экспоненциальной задержкой.
  4. Использовать асинхронные или конкурентные механизмы 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, не перегружая систему и не вызывая блокировки со стороны сервера.