如何有效关闭渠道?

时间:2017-06-30 10:47:29

标签: go concurrency goroutine

我正在尝试做一些事情:

type Feed struct {
    title, descr, link string
    published          time.Time
}
func main() {
    ar := make([]Feed, 0)
    for i := 0; i < 3; i++ {
        f: = new(Feed)
        // do some stuff with feed
        ar = append(ar, *f)
    }

    ch := make(chan Feed, 3)

    for _, i := range ar {
        go process(i, ch)
    }

    r :=0
    for i := range ch {
        fmt.Println(i)
        r++
        if r == 3 {
            close(ch)
        }
    }
}
func process(i Feed, ch chan Feed) {
 // do some stuff
 ch <- i
}

似乎ar是不必要的,但如果将其删除,则最后一个范围将是永久的。我做错了什么?

另一个问题是 - 以正确的方式使用Go例程吗?

1 个答案:

答案 0 :(得分:2)

以下是生产者 - 消费者类型的示例。我只在这里使用WaitGroup,这样主要的goroutine就不会立即退出。从理论上讲,你的应用程序可以等待,或者同时做一些其他有趣的事情。

请注意,您还可以使用c := make(chan(*Feed, n))使用缓冲频道,其中n是您要缓冲的数字。请注意,在典型的生产者 - 消费者场景中,每个作业有时会分配大量资源。因此,根据您的需要,您可以缓冲一些或全部缓冲。

如果没有缓冲通道,它将充当goroutines之间的同步。生产者阻止c <-等待消费者<- c交出,所以每个例程中只有一个一次执行这些行。

编辑我在打印之前添加了暂停&#34;开始&#34;使输出更少同步。它以前总是输出:

created
started
created
started
...

https://play.golang.org/p/FmWqegr-CR

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

type Feed struct {
    title, descr, link string
    published          time.Time
}

func CreateFeed() *Feed {
    r := rand.Int() % 500
    time.Sleep(1000 + time.Duration(r)*time.Millisecond)
    fmt.Println("Feed created")
    return &Feed{
        published: time.Now(),
    }
}

func UseFeed(f *Feed) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("Feed started")
    time.Sleep(1600 * time.Millisecond)
    fmt.Printf("Feed consumed: %s\n", f.published)
}

func main() {
    numFeeds := 10

    var wg sync.WaitGroup
    wg.Add(10)

    c := make(chan (*Feed))
    for i := 0; i < numFeeds; i++ {
        go func() { c <- CreateFeed() }()
    }

    for i := 0; i < numFeeds; i++ {
        go func() {
            f := <-c
            UseFeed(f)
            wg.Done()
        }()
    }

    wg.Wait()
}

我希望这就是你要找的东西。