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.