Hi Marcin, I think https://play.golang.org/p/RiKi1PGVSvF is basically what I do with atomic operations in my blog post https://dev.to/leolara/closing-a-go-channel-written-by-several-goroutines-52j2 in the section "Some experiments", and then using the wait group as I say later in the section "The solution involves wait groups",
I think it is more constrained than my final solution because: + You need to make sure that all producers have started (run Add(1)) before you call Close. You would need to use a mutex around Add and Wait to solve this, I think now that a RWLock have the read arround Add(1) and the write around Wait could be better. + All writing goroutines will stay blocked until a reader reads all, using a closing channel is better because you can use select and they could unblock without a reader. On Wednesday, August 28, 2019 at 10:37:52 PM UTC+2, Marcin Romaszewicz wrote: > > Think of a channel as existing for the lifetime of a particular data > stream, and not have it be associated with either producer or consumer. > Here's an example: > > https://play.golang.org/p/aEAXXtz2X1g > > The channel here is closed after all producers have exited, and all > consumers continue to run until the channel is drained of data. > > The producers are managed by something somewhere in your code - and that > is the scope at which it makes sense to create channel ownership. I've used > a waitgroup to ensure that the channel is closed after all producers exit, > but you can use whatever barrier construct you want. > > Even if you must have a channel per producer, you can safely close the > producer side, without notifying the downstream about this. The example > early in the thread uses multiple channels, with one channel being used to > signal that the producers should exit. Channels aren't really the right > model for this, you want a thread safe flag of some sort. For example: > > var exitFlag uint64 > func producer(chan data int, wg *sync.WaitGroup) { > defer wg.Done() > for { > shouldExit := atomic.LoadUint64(&exitFlag) > if shouldExit == 1 { > return > } > chan <- rand.Intn(100) > } > } > > Here's 10 producers and 3 consumers sharing a channel and closing it > safely upon receiving an exit flag: > https://play.golang.org/p/RiKi1PGVSvF > > -- Marcin > > On Wed, Aug 28, 2019 at 11:29 AM Leo Lara <l...@leopoldolara.com > <javascript:>> wrote: > >> I do not think priority select is *necessary*, it could be a nice >> addition if the performance does not change. >> >> On Wednesday, August 28, 2019 at 8:27:36 PM UTC+2, Leo Lara wrote: >>> >>> Hi Robert, >>> >>> From the article: """To bound more the problem, in my case, you control >>> the writers but not the readers""" >>> >>> So what I was trying to do was to be able to close, with mutiple >>> writers, while being transparent for the readers. The readers only need to >>> read as usual form the channel. >>> >>> For example, if you want to write a library where the user just reads >>> from a channel, this is an approach I found where the user of the lirbary >>> deos nto have to do anything special. Of course, there might be another >>> solution, but if you need to modify the reader we are talking about a >>> different problem. >>> >>> Cheers!! >>> >>> On Wednesday, August 28, 2019 at 7:17:24 PM UTC+2, Robert Engels wrote: >>>> >>>> A better solution is to wrap the writes using a RWLock, grab the read >>>> lock for writing, and the Write lock for closing. Pretty simple. >>>> >>>> Just encapsulate it all in a MultiWriterChannel struct - generics would >>>> help here :) >>>> >>>> -----Original Message----- >>>> From: Leo Lara >>>> Sent: Aug 28, 2019 11:24 AM >>>> To: golang-nuts >>>> Subject: [go-nuts] Re: An old problem: lack of priority select cases >>>> >>>> This is connected with my article: >>>> https://dev.to/leolara/closing-a-go-channel-written-by-several-goroutines-52j2 >>>> >>>> I think there I show it is possible to workaround that limitation using >>>> standard Go tools. Of course, the code would be simple with priority >>>> select, but also perhaps select would become less efficient. >>>> >>>> On Wednesday, August 28, 2019 at 6:06:33 PM UTC+2, T L wrote: >>>>> >>>>> The old thread: >>>>> https://groups.google.com/forum/#!topic/golang-nuts/ZrVIhHCrR9o >>>>> >>>>> Go channels are flexible, but in practice, I often encountered some >>>>> situations in which channel are hard to use. >>>>> Given an example: >>>>> >>>>> import "math/rand" >>>>> >>>>> type Producer struct { >>>>> data chan int >>>>> closed chan struct{} >>>>> } >>>>> >>>>> func NewProducer() *Producer { >>>>> p := &Producer { >>>>> data: make(chan int), >>>>> closed: make(chan struct{}), >>>>> } >>>>> >>>>> go p.run() >>>>> >>>>> return p >>>>> } >>>>> >>>>> func (p *Produce) Stream() chan int { >>>>> return p.data >>>>> } >>>>> >>>>> func (p *Producer) run() { >>>>> for { >>>>> // If non-blocking cases are selected by their appearance >>>>> order, >>>>> // then the following slect block is a perfect use. >>>>> select { >>>>> case(0) <-p.closed: return >>>>> case p.data <- rand.Int(): >>>>> } >>>>> } >>>>> } >>>>> >>>>> func (p *Produce) Clsoe() { >>>>> close(p.closed) >>>>> close(p.data) >>>>> } >>>>> >>>>> func main() { >>>>> p := NewProducer() >>>>> for n := p.Stream() { >>>>> // use n ... >>>>> } >>>>> } >>>>> >>>>> >>>>> If the first case in the select block in the above example has a >>>>> higher priority than the second one, >>>>> then coding will be much happier for the use cases like the above one. >>>>> >>>>> In short, the above use case requires: >>>>> * for receivers, data streaming end is notified by the close of a >>>>> channel. >>>>> * for senders, data will never be sent to closed channel. >>>>> >>>>> But, as Go 1 doesn't support priority select cases, it is much tedious >>>>> to implement the code >>>>> satisfying the above listed requirements. The final implementation is >>>>> often very ugly and inefficient. >>>>> >>>>> Does anyone else also experience the pain? >>>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to golan...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/golang-nuts/b284f880-034a-4721-8686-ef48d3e2c14c%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/golang-nuts/b284f880-034a-4721-8686-ef48d3e2c14c%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>>> >>>> >>>> >>>> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golan...@googlegroups.com <javascript:>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/aeb38a0a-8268-42d7-a8eb-ce5ef01c5380%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/aeb38a0a-8268-42d7-a8eb-ce5ef01c5380%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/aedd5ef7-1663-4eb9-b86c-d12499d37b3d%40googlegroups.com.