当向通道写入数据时,永远不会调用”defer”。

huangapple go评论106阅读模式
英文:

Defer never called when writing to channel

问题

我正在尝试在goroutine函数的最后一个操作中向通道写入数据。

不幸的是,这并没有起作用,而且等待组永远不会完成。

  1. import (
  2. "sync"
  3. "github.com/SlyMarbo/rss"
  4. "fmt"
  5. )
  6. func main() {
  7. urls := []string{"http://rss.cnn.com/rss/edition.rss", "http://rss.time.com/web/time/rss/top/index.xml"}
  8. var c = make(chan string)
  9. var wg sync.WaitGroup
  10. for _, url := range urls {
  11. wg.Add(1)
  12. go receiveRss(url, &wg, c)
  13. }
  14. wg.Wait()
  15. fmt.Println("==============DONE=================")
  16. }
  17. func receiveRss(url string, wg *sync.WaitGroup, c chan string) {
  18. defer wg.Done()
  19. feed, err := rss.Fetch(url)
  20. if err != nil {
  21. fmt.Println("Failed to retrieve RSS feed", err)
  22. }
  23. items := feed.Items
  24. for _, item := range items {
  25. c <- item.Title
  26. }
  27. }

当将c <- item.Title替换为fmt.Println(item.Title)时,延迟函数被调用并打印出"DONE"。

英文:

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.

  1. import (
  2. &quot;sync&quot;
  3. &quot;github.com/SlyMarbo/rss&quot;
  4. &quot;fmt&quot;
  5. )
  6. func main() {
  7. urls := []string{&quot;http://rss.cnn.com/rss/edition.rss&quot;, &quot;http://rss.time.com/web/time/rss/top/index.xml&quot;}
  8. var c = make(chan string)
  9. var wg sync.WaitGroup
  10. for _, url := range urls {
  11. wg.Add(1)
  12. go receiveRss(url, &amp;wg, c)
  13. }
  14. wg.Wait()
  15. fmt.Println(&quot;==============DONE=================&quot;)
  16. }
  17. func receiveRss(url string, wg *sync.WaitGroup, c chan string) {
  18. defer wg.Done()
  19. feed, err := rss.Fetch(url)
  20. if err != nil {
  21. fmt.Println(&quot;Failed to retrieve RSS feed&quot;, err)
  22. }
  23. items := feed.Items
  24. for _, item := range items {
  25. c &lt;- item.Title
  26. }
  27. }

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

答案1

得分: 1

问题是我只是向通道写入数据,从未从中读取数据。
如果不这样做,通道将是无用的。

解决方法是:

在启动goroutine的循环之后从通道中读取数据:

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

这会导致无限循环,如果通道从未关闭。
所以我在写入数据后关闭通道:

  1. close(c)

以下是完整的代码:

  1. func main() {
  2. urls := []string{"http://rss.cnn.com/rss/edition.rss", "http://rss.time.com/web/time/rss/top/index.xml"}
  3. var c = make(chan []string)
  4. var wg sync.WaitGroup
  5. for _, url := range urls {
  6. wg.Add(1)
  7. go receiveRss(url, &wg, c)
  8. }
  9. for title := range c {
  10. fmt.Println(title)
  11. }
  12. wg.Wait()
  13. fmt.Println("==============DONE=================")
  14. }
  15. func receiveRss(url string, wg *sync.WaitGroup, c chan []string) {
  16. defer wg.Done()
  17. feed, err := rss.Fetch(url)
  18. if err != nil {
  19. fmt.Println("Failed to retrieve RSS feed", err)
  20. }
  21. items := feed.Items
  22. var titles []string
  23. for _, item := range items {
  24. titles = append(titles, item.Title)
  25. }
  26. c <- titles
  27. close(c)
  28. }
英文:

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:

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

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

  1. close(c)

Here is the whole code:

  1. func main() {
  2. urls := []string{&quot;http://rss.cnn.com/rss/edition.rss&quot;, &quot;http://rss.time.com/web/time/rss/top/index.xml&quot;}
  3. var c = make(chan []string)
  4. var wg sync.WaitGroup
  5. for _, url := range urls {
  6. wg.Add(1)
  7. go receiveRss(url, &amp;wg, c)
  8. }
  9. for title := range c {
  10. fmt.Println(title)
  11. }
  12. wg.Wait()
  13. fmt.Println(&quot;==============DONE=================&quot;)
  14. }
  15. func receiveRss(url string, wg *sync.WaitGroup, c chan []string) {
  16. defer wg.Done()
  17. feed, err := rss.Fetch(url)
  18. if err != nil {
  19. fmt.Println(&quot;Failed to retrieve RSS feed&quot;, err)
  20. }
  21. items := feed.Items
  22. var titles []string
  23. for _, item := range items {
  24. titles = append(titles, item.Title)
  25. }
  26. c &lt;- titles
  27. close(c)
  28. }

huangapple
  • 本文由 发表于 2017年5月3日 03:16:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/43745595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定