如何高效关闭通道?

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

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 &lt; 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 &lt;- 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 &lt;- waiting for a consumer's &lt;- 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 (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

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(&quot;Feed created&quot;)
	return &amp;Feed{
		published: time.Now(),
	}
}

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

func main() {
	numFeeds := 10

	var wg sync.WaitGroup
	wg.Add(10)

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

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

	wg.Wait()
}

I'm hoping this is what you are looking for.

huangapple
  • 本文由 发表于 2017年6月30日 18:47:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/44844654.html
匿名

发表评论

匿名网友

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

确定