Неизвестное число URL удобно передавать каналом: источник закрывает его по окончании, работники завершаются, а координатор закрывает результаты после WaitGroup.
Напишите программу, которая:
Неизвестное число URL удобно передавать каналом: источник закрывает его по окончании, работники завершаются, а координатор закрывает результаты после WaitGroup.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Напишите программу, которая:
-
Поочередно выполнит http запросы по предложенному списку ссылок • в случае получения http-кода ответа на запрос "200 OK" печатаем на экране "адрес url - ok" • в случае получения http-кода ответа на запрос отличного от "200 OK" либо в случае ошибки печатаем на экране "адрес url - not ok"
-
Модифицируйте программу таким образом, чтобы использовались каналы для коммуникации основного потока с горутинами. Пример: Запросы по списку выполняются в горутинах. Печать результатов на экран происходит в основном потоке.
-
Модифицируйте программу таким образом, чтобы нигде не использовалась длина слайса урлов. Считайте, что урлы приходят из внешнего источника. Сколько их будет заранее - неизвестно. Предложите идиоматичный вариант, как ваша программа будет узнавать об окончании списка и передавать сигнал об окончании действий далее.
Ответ
Неизвестное число URL удобно передавать каналом: источник закрывает его по окончании, работники завершаются, а координатор закрывает результаты после WaitGroup.
Ниже Go-программа без использования len(urls). При workers=1 запросы последовательны; большее число включает ограниченный параллелизм. Печатает основная горутина.
package main
import (
"fmt"
"net/http"
"sync"
"time"
)
type Result struct { URL string; OK bool }
func check(client *http.Client, url string) Result {
resp, err := client.Get(url)
if err != nil { return Result{URL: url} }
defer resp.Body.Close()
return Result{URL: url, OK: resp.StatusCode == http.StatusOK}
}
func run(urls <-chan string, workers int) {
if workers < 1 { panic("workers must be positive") }
client := &http.Client{Timeout: 5 * time.Second}
out := make(chan Result)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for url := range urls { out <- check(client, url) }
}()
}
go func() { wg.Wait(); close(out) }()
for r := range out {
status := "not ok"
if r.OK { status = "ok" }
fmt.Printf("%s - %s\n", r.URL, status)
}
}
func main() {
urls := make(chan string)
go func() {
defer close(urls)
// Здесь может находиться чтение внешнего источника до EOF.
for _, url := range []string{"https://example.com", "https://example.org"} {
urls <- url
}
}()
run(urls, 3)
}
Вывод при параллельной работе идёт по готовности. Источник обязан закрыть канал после завершения; для прекращения незавершённого внешнего источника дополнительно нужен общий context.