如何有效关闭频道?

问题描述:

我试图做一些东西:如何有效关闭频道?

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例程一起工作的方式是否正确?

+0

这个具体的例子很容易用'sync.WaitGroup'完成,而不需要任何通道。渠道通常用于提供者 - 消费者类型的应用程序中,其中您有一个或多个创建任务的例程以及一个或多个执行任务的例程。所以我的澄清问题是:你的代码创建'Feed'是否需要足够的时间让它对于'Feed'的创建和使用都有帮助? “使用饲料做某些事情”是否真的需要时间? – RayfenWindspear

+0

@RayfenWindspear谢谢你的回复,是的“做一些饲料的东西”可以花费很多时间,所以我想尽快从处理饲料中获得结果,我不想等到所有的日常活动都会完成 – inJakuzi

+0

请粘贴你删除了代码。 – mattn

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

请注意,您也可以使用c := make(chan(*Feed, n))的缓冲通道,其中n是您想要缓冲的数量。请注意,在典型的生产者 - 消费者场景中,每个作业有时会分配大量资源。所以取决于你可以缓冲一些,或者如果你想要缓冲的话。

没有缓冲通道,它充当goroutine之间的同步。生产者阻止c <-等待消费者的<- c切换到,因此每次只有一个例程一次执行这些行。

编辑我在打印“开始”之前添加了一个暂停,以使输出更少同步。它以前一直输出:

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() 
} 

我希望这是你在找什么。

+0

看起来像我真的需要,谢谢。 还有一个问题:在使用goroutines时,sync.WaitGroup是主要的东西,我看到很多与goroutines和WG在一起的例子,但在golangtour中没有关于WG的信息 – inJakuzi

+0

@inJakuzi在我看来,这不是真正的方法,一个骗子的方式来做到这一点。不要误解我的意思,它绝对有其用处,但它会浪费主程序的时间。我在这里做得更快,所以我为此道歉。我通常会这样做(假设主例程继续使用结果),可能会将第二个循环插入主线程将从中获取的结果通道。这样,只要完成一次,而不是'wg.Wait()'就可以开始整个结果集。 – RayfenWindspear

+0

处理并发性时需要记住很多细微的事情,但最大的一个显然(有时候并不那么明显)想要尽可能少地等待。因此,我厌恶'wg.Wait()'。 – RayfenWindspear