I see some smart people suggesting that what OP is doing is not
correct.  I am going to cautiously disagree with some of those replies
and suggest that a similar pattern can be useful for some
applications.

We have an application where we have a similar need.  Specifically,
there is a periodic ticker goroutine that calculates the value to send
and there is an IO goroutine that performs i/o with the latest value
(and that i/o could block for an unknown amount of time.  It is OK to
drop values that are not the most recent values, but we would like to
have the i/o happen as quickly as possible after the calculation.  As
an example, imagine an application that cares about soft realtime
responsiveness like telephony or multiplayer gaming (those
applications would probably be OK using UDP for example).

For a long time we used some shared memory for the value protected by
a mutex.  Then the signaling would be performed using a condition
variable.  That worked OK, but we also wanted to have a way to queue a
value if i/o is in progress and have a second round of i/o start
immediately after the first one returns so we needed another indicator
for that.  We ended up using a pointer to the value where the nil
pointer could represent that no new value is waiting.  We ran with
that code for years and it worked, but was a little subtle and hard to
follow.

Eventually I rewatched Bryan Mill's excellent "Rethinking Classical
Concurrency" talk (https://www.youtube.com/watch?v=5zXAHh5tJqQ) and
tried to think about how to apply some of those ideas to the problem
instead of using the condition variable.  My initial solution was
similar to some of the ideas in the talk and have 2 channels: 1 as a
semaphore to control the "direction" of the flow and the other channel
with the value.  Thinking about it more, the thing being sent over the
"semaphore" channel could actually be the value itself as long as only
one goroutine is doing the sending.  That simplifies the design down
to a single channel.  The pattern we ended up looks like this:
https://play.golang.org/p/m6ONLGZ7nU2

There are a few caveats with that solution:
 - Only one goroutine can do the triggering and sending on the channel
(if you wanted to have multiple sending goroutines, then I think the
multiple channel semaphore pattern can work).
 - With a single channel (and single goroutine trigger) solution, the
buffered channel should be drained unconditionally by the triggering
goroutine in a non-blocking way before each send of a new value.
 - There is a logical race (not a data race) between the triggering
goroutine and the i/o goroutine and the values that actually get sent
will be subject to the i/o delays and goroutine scheduler.  Your
application must be OK with that (that was acceptable for our
application).

Best,
Tarmigan

On Fri, Nov 13, 2020 at 7:19 AM Ian Lance Taylor <i...@golang.org> wrote:
>
> On Thu, Nov 12, 2020 at 11:13 PM 陶青云 <qingyu...@gmail.com> wrote:
> >
> >
> > It is not a one-length buffered channel.  I need to drop because the 
> > recveiver do heavy work that can't process as quickly as sender.
>
> Don't use channels for this.  It's not what they are for.
>
> Ian
>
>
>
> > 在2020年11月13日星期五 UTC+8 下午2:36:13<Kurtis Rader> 写道:
> >>
> >> On Thu, Nov 12, 2020 at 9:32 PM 陶青云 <qing...@gmail.com> wrote:
> >>>
> >>> Thanks. I want the receiver always get the relately new vaule,  I don't 
> >>> want the sender blocked and I either choose drop the current value or the 
> >>> first value of the channel. But I don't find a way to safely drop the 
> >>> first value from the channel.
> >>
> >>
> >> You seem to be talking about a buffered channel of length one. If that is 
> >> true why are you using a channel? You can instead use a simple var 
> >> protected by a mutex. If you're talking about a buffered channel with size 
> >> greater than one it is unclear why a full channel should drop the first 
> >> entry in the channel rather than multiple (even all) entries in the queue. 
> >> This seems like an XY problem.
> >>
> >>>
> >>> Maybe like this ?
> >>
> >>
> >> No, since that "solution" just replaces one race with another.
> >>
> >> --
> >> Kurtis Rader
> >> Caretaker of the exceptional canines Junior and Hank
> >
> > --
> > 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/5f5cb0c2-54e9-4d5f-bbc7-43c902615b8fn%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/CAOyqgcUjEPj3%2BWFpnBsgiPvKMZqbpNn%3DM1-eN6m6B4bXtvRp7A%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 golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAE1MmuHmdLOQCjkFY0R%2BWsaMm4NuGmumqGdXCGQzC0Nw4fLYLQ%40mail.gmail.com.

Reply via email to