Наилучшее время для закрытия канала при итерации по каналу - PullRequest
1 голос
/ 14 июня 2019

Я играю с Голангом и создал это маленькое приложение, чтобы совершать несколько одновременных вызовов API с помощью goroutines.

Пока приложение работает, после завершения вызовов приложение застревает, что имеет смысл, поскольку оно не может выйти из цикла range c , поскольку канал не закрыт.

Я не уверен, где лучше закрыть канал в этом паттерне.

package main

import "fmt"
import "net/http"

func main() {
    links := []string{
        "https://github.com/fabpot",
        "https://github.com/andrew",
        "https://github.com/taylorotwell",
        "https://github.com/egoist",
        "https://github.com/HugoGiraudel",
    }

    checkUrls(links)
}

func checkUrls(urls []string) {
    c := make(chan string)

    for _, link := range urls {
        go checkUrl(link, c)
    }

    for msg := range c {
        fmt.Println(msg)
    }

    close(c) //this won't get hit
}

func checkUrl(url string, c chan string) {
    _, err := http.Get(url)

    if err != nil {
        c <- "We could not reach:" + url
    } else {
        c <- "Success reaching the website:" + url
    }
} 

Ответы [ 2 ]

6 голосов
/ 14 июня 2019

Вы закрываете канал, когда больше нет значений для отправки, так что в этом случае это когда все процедуры checkUrl завершены.

var wg sync.WaitGroup

func checkUrls(urls []string) {
    c := make(chan string)

    for _, link := range urls {
        wg.Add(1)
        go checkUrl(link, c)
    }

    go func() {
        wg.Wait()
        close(c)
    }()

    for msg := range c {
        fmt.Println(msg)
    }
}

func checkUrl(url string, c chan string) {
    defer wg.Done()
    _, err := http.Get(url)

    if err != nil {
        c <- "We could not reach:" + url
    } else {
        c <- "Success reaching the website:" + url
    }
}

(Обратите внимание, что error из http.Get будет отражать только ошибки соединения и протокола. Он не будет содержать ошибок http-сервера, если вы ожидаете их тоже, что вы должны видеть, как вы проверка путей, а не только хостов.)

1 голос
/ 15 июня 2019

При написании программ на Go с использованием каналов и программ всегда думайте о том, кому (какой функции) принадлежит канал. Я предпочитаю, чтобы функция, которая владеет каналом, закрывала его. Если бы я написал это, я бы сделал, как показано ниже.

Примечание. Лучший способ справиться с подобными ситуациями - шаблон одновременного исполнения fan-in, fan-in . см. (https://blog.golang.org/pipelines) Шаблоны Go Concurrency

package main

import "fmt"
import "net/http"
import "sync"

func main() {
    links := []string{
        "https://github.com/fabpot",
        "https://github.com/andrew",
        "https://github.com/taylorotwell",
        "https://github.com/egoist",
        "https://github.com/HugoGiraudel",
    }


    processURLS(links)
    fmt.Println("End of Main")
}

func processURLS(links []string) {
    resultsChan := checkUrls(links)

    for msg := range resultsChan {
        fmt.Println(msg)
    }

}     

func checkUrls(urls []string) chan string {

    outChan := make(chan string)

    go func(urls []string) {
       defer close(outChan)

       var wg sync.WaitGroup
       for _, url := range urls {
         wg.Add(1)
          go checkUrl(&wg, url, outChan)
       }
       wg.Wait()

    }(urls)

    return outChan
}

func checkUrl(wg *sync.WaitGroup, url string, c chan string) {
    defer wg.Done()
    _, err := http.Get(url)

    if err != nil {
        c <- "We could not reach:" + url
    } else {
        c <- "Success reaching the website:" + url
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...