英文:
How to efficiently close the channel?
问题
我正在尝试做一些事情:
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)
// 对 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) {
// 进行一些操作
ch <- i
}
看起来 ar
是不必要的,但如果将其删除,最后的 range 循环将会无限进行。我做错了什么?
另一个问题是,这种使用 Go 协程的方式是否正确?
英文:
I'm trying to do some stuff:
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
}
It seems that ar
is unnecessary, but if it would be removed, last range would be forever. What i'm doing wrong?
Another question is - is that way of working with Go routines the right way?
答案1
得分: 2
这是一个生产者-消费者类型的示例。我在这里只使用WaitGroup
,以防止主goroutine立即退出。理论上,您的应用程序可以等待,或者在此期间执行一些其他有趣的操作。
请注意,您还可以使用带缓冲的通道,使用c := make(chan(*Feed, n))
,其中n
是您想要缓冲的数量。只需注意,在典型的生产者-消费者场景中,每个作业有时会分配大量资源。因此,根据情况,您可以只缓冲一部分作业,或者如果需要的话,全部缓冲。
没有缓冲的通道充当goroutine之间的同步。生产者在c <-
处阻塞,等待消费者的<- c
来接收,因此每次只有一个例程执行这些行。
编辑:我在打印“started”之前添加了一个暂停,以使输出不那么同步。以前的输出总是:
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()
}
希望这是您要找的内容。
英文:
Here is an example producer-consumer type. I only use the WaitGroup
here so that the main goroutine wouldn't exit instantly. Theoretically your application could either wait, or do some other interesting stuff in the mean time.
Note that you could also use a buffered channel using c := make(chan(*Feed, n))
where n
is the number you want buffered. Just be aware that in a typical producer-consumer scenario, there is sometimes a lot of resources allocated per job. So depending on that you could buffer just a few, or all of them if you wanted.
Without a buffered channel, it acts as a sync between the goroutines. Producers block at c <-
waiting for a consumer's <- c
to hand off to, so only one of each routine execute these lines at a time.
EDIT I added a pause before printing "started" to make the output less synchronized. It previously always output:
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()
}
I'm hoping this is what you are looking for.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论