crawler.go en Go
Descarga varias URL de forma concurrente y reporta cada resultado.
// Descarga varias URLs de forma concurrente y reporta estado y tamaño.
package main
import (
"fmt"
"io"
"net/http"
"sync"
"time"
)
type result struct {
url string
status int
size int
err error
}
func fetch(url string, client *http.Client) result {
resp, err := client.Get(url)
if err != nil {
return result{url: url, err: err}
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
return result{
url: url,
status: resp.StatusCode,
size: len(body),
err: err,
}
}
func main() {
urls := []string{
"https://example.com",
"https://example.org",
"https://example.net",
}
client := &http.Client{Timeout: 10 * time.Second}
results := make(chan result, len(urls))
var wg sync.WaitGroup
start := time.Now()
for _, url := range urls {
wg.Add(1)
go func(u string) {
defer wg.Done()
results <- fetch(u, client)
}(url)
}
wg.Wait()
close(results)
for r := range results {
if r.err != nil {
fmt.Printf("%-24s error: %v\n", r.url, r.err)
continue
}
fmt.Printf("%-24s %d %d bytes\n", r.url, r.status, r.size)
}
elapsed := time.Since(start).Round(time.Millisecond)
fmt.Printf("fetched %d urls in %s\n", len(urls), elapsed)
}
Cómo funciona
- Una goroutine por URL envía a un canal con búfer.
- Un struct
resultlleva el estado, el tamaño o el error. WaitGroupy luego close dejan que el lector lo drene.
Palabras clave y builtins usados aquí
chanclosecontinuedefererrorforfuncgoifintlenmakerangereturnstringstructtypevar
El intento, en números
- Líneas
- 67
- Caracteres a escribir
- 1139
- Tokens
- 294
- Ritmo de tres estrellas
- 110 tpm
Al ritmo de tres estrellas de 110 tokens por minuto, este intento toma unos 160 segundos.
Paso 1 de 2 en Bis; paso 24 de 25 en Concurrencia.