Marcel Bochtler
Marcel Bochtler

Reputation: 1361

Defer never called when writing to channel

I'm trying to write to a channel as last action in a goroutine function.

Unfortunately this is not working. And the waitGroup is never done.

import (
    "sync"
    "github.com/SlyMarbo/rss"
    "fmt"
)

func main() {
    urls := []string{"http://rss.cnn.com/rss/edition.rss", "http://rss.time.com/web/time/rss/top/index.xml"}

    var c = make(chan string)
    var wg sync.WaitGroup
    for _, url := range urls {
        wg.Add(1)
        go receiveRss(url, &wg, c)
    }
    wg.Wait()
    fmt.Println("==============DONE=================")
}

func receiveRss(url string, wg *sync.WaitGroup, c chan string) {
    defer wg.Done()
    feed, err := rss.Fetch(url)
    if err != nil {
        fmt.Println("Failed to retrieve RSS feed", err)
    }

    items := feed.Items
    for _, item := range items {
        c <- item.Title
    }
}

When replacing c <- item.Title with fmt.Println(item.Title) the deferred function is called and DONE is printed.

Upvotes: 1

Views: 3496

Answers (1)

Marcel Bochtler
Marcel Bochtler

Reputation: 1361

The problem is that I was only writing to the channel. Never reading from it. Without doing this the channel would be useless.

The solution to this is:

Reading from the channel after the loop which starts the goroutines:

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

This then causes an endless loop if the channel is never closed. So I just close the channel after writing to it:

close(c)

Here is the whole code:

func main() {

    urls := []string{"http://rss.cnn.com/rss/edition.rss", "http://rss.time.com/web/time/rss/top/index.xml"}

    var c = make(chan []string)
    var wg sync.WaitGroup

    for _, url := range urls {
        wg.Add(1)
        go receiveRss(url, &wg, c)
    }
    for title := range c {
        fmt.Println(title)
    }
    wg.Wait()
    fmt.Println("==============DONE=================")
}

func receiveRss(url string, wg *sync.WaitGroup, c chan []string) {
    defer wg.Done()
    feed, err := rss.Fetch(url)
    if err != nil {
        fmt.Println("Failed to retrieve RSS feed", err)
    }

    items := feed.Items
    var titles []string
    for _, item := range items {
        titles = append(titles, item.Title)
    }
    c <- titles
    close(c)
}

Upvotes: 1

Related Questions