I will repeat this - and I meant no offense. You should read up on RWLocks because your criticism is incorrect. Multiple Go readers can hold the Read lock at the same time - so there are multiple writers adding to the channel concurrently (but the channel impl uses a lock, so it’s not strictly true, if they used a lock free queue then it would be)
> On Sep 4, 2019, at 4:55 AM, Leo Lara <l...@leopoldolara.com> wrote: > > > >> You should read up on how a RWLock works. > > I am not going to answer to that ;-) > > About this code: > > https://play.golang.org/p/YOwuYFiqtlf > > 1. I wouldn't say that there are several goroutines writing, as there are > several goroutines block in a mutex. Some might find this not important, > although there are some people that have looked into this and think it is > less efficient > https://opensource.com/article/18/7/locks-versus-channels-concurrent-go ; I > think it has to do on how the scheduler changes to another goroutine when the > goroutine is lock on a channel. > 2. More importantly IMHO, in your example the reader has to be aware that > there is a lock. Hence, it is not "transparent" in the sense that the reader > has to share something with the writer > >> >> The Sleep(1) in the producer is only to add some delay to demonstrate it >> gets terminated before the desired number of iterations. >> >>> On Aug 29, 2019, at 12:13 AM, Leo Lara <l...@leopoldolara.com> wrote: >>> >>> Hi Robert, >>> >>> To put you in context, it all started when I read >>> https://go101.org/article/channel-closing.html , that said that it is >>> impossible or at least you shouldn't close a channel that is being written >>> by several goroutines. Then I wrote this article with my solution >>> https://dev.to/leolara/closing-a-go-channel-written-by-several-goroutines-52j2 >>> also in >>> https://medium.com/@leolara/closing-a-go-channel-written-by-several-goroutines-eba3a6c9404b >>> I then created this issue https://github.com/go101/go101/issues/132 and >>> from there this topic was created by T L. >>> >>> Your example does not have several goruitnes writing so I think it is a >>> different problem. Perhaps that simple lock would work with several >>> goroutines, but I think there would be more contention with this lock. >>> >>> Anyway, I think I have already an optimisation to my code, I think using a >>> RW lock, if I put the "Add(1)" in a read lock and the wait in a Write lock >>> it might work better. The race condition that my lock prevents is only >>> related when an "Add" and a "Wait" run concurrently, several "Add" can run >>> concurrently. >>> >>>> On Thursday, August 29, 2019 at 4:05:06 AM UTC+2, robert engels wrote: >>>> Here is a version using RWLock https://play.golang.org/p/YOwuYFiqtlf >>>> >>>> It won’t run correctly in the playground because it terminates when all >>>> routines are asleep - which happens during the test (not sure why it does >>>> this, as sleeping is different than a deadlock). >>>> >>>> It is probably less efficient, and less orderly than the other example >>>> using WaitGroup but you get the idea I hope. It forcibly terminates the >>>> writers before they complete by design. >>>> >>>>> On Aug 28, 2019, at 4:09 PM, Michel Levieux <m.le...@capitaldata.fr> >>>>> wrote: >>>>> >>>>> One should also be careful regarding the conceptual demands he or she is >>>>> making. >>>>> Having a shared resource (that is complex enough that it cannot be >>>>> atomically accessed or modified) means essentially that "having multiple >>>>> writers being transparent to the readers", fundamentally, is not possible. >>>>> >>>>> From the moment itself when such a resource is shared, there must be some >>>>> sort of mecanism (that one using resources atomically usable) that >>>>> ensures the integrity of it. >>>>> Maybe what you're talking about is having it transparent in terms of >>>>> code, in which case we both agree, but if you're looking for something >>>>> transparent in essence, as in performance, logical construction and all >>>>> the rest, I think there is a misunderstanding here: even if it was added >>>>> in the language, there would be many many things going on under the hood, >>>>> as it is already (and cannot really be otherwise) for channel use alone. >>>>> >>>>> As for the priority using selects, I think it's more of something to be >>>>> dealt with on the "user-side". There are many kinds of priority in >>>>> general, and trying to implement something in the language itself would >>>>> IMO either be too specific compared to the nessecary time to do so or it >>>>> would probably have a huge overhead on the "classical' use case of the >>>>> select construct. >>>>> + the fact that it is apparently already possible using RWMutexes. >>>>> >>>>>> Le mer. 28 août 2019 à 22:37, Marcin Romaszewicz <mar...@gmail.com> a >>>>>> écrit : >>>>>> 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> 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. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> 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/aeb38a0a-8268-42d7-a8eb-ce5ef01c5380%40googlegroups.com. >>>>>> >>>>>> >>>>>> -- >>>>>> 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/CA%2Bv29LvcUhUvrZb_8AKYWj0A%2Bqd5LKBPmbz-RVBb%3DJn_gNZE6w%40mail.gmail.com. >>>>> >>>>> >>>>> -- >>>>> 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/CANgi337s1Low95QvqJUAOTsqcVji7uMQ_jr%3DFftpt2uMz5_XSQ%40mail.gmail.com. >>>> >>> >>> -- >>> 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/e5f37679-bdfb-4da3-854e-fea35cf82cb7%40googlegroups.com. > > -- > 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/8893737c-148e-4d64-9a0c-cd72046cd0d1%40googlegroups.com. -- 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/34F5C212-9269-414E-87BC-8850382EA5BC%40ix.netcom.com.