Go channels overused and hyped?

1,957 views
Skip to first unread message

snmed

unread,
Aug 8, 2017, 2:01:12 AM8/8/17
to golang-nuts
Hi Gophers

I stumbled over a nice and very interesting Blog entry "Go channels are bad and you should feel bad" , I would like to hear some opinions about that article
from seasoned go developers. Because I just used go for a couple of months for my private web projects and rarely get in touch with channels.

By the way, that article is not a rant and the author likes go very much as far as I can conclude from the article.

Cheers snmed

Egon

unread,
Aug 8, 2017, 3:26:35 AM8/8/17
to golang-nuts
There are trade-offs.

Channels are easy to use for simple things, but complicated for complected things.

Locking data-structures can easily introduce data-races (see The Little Book of Semaphores http://greenteapress.com/wp/semaphores/).

The Game/Player example looks weird to me; there's one piece missing -- without it, the full complexity is not seen.

With regards to callbacks (context.Done) specifically, in one case you control the goroutine it gets executed in, in the other not.

Not closing the waiting channel inside context leaking goroutine is moot... when you forget to invoke the callbacks, you will leak as well when you have resource releasing in the callback.

Channels are quite good for producer-consumer things, but tend to get very complicated for dispatches.

tl;dr; channels and locking have trade-offs, instead of hopping on the bandwagon, understand the trade-offs and pick the one that is most suitable in a certain situation.

+ Egon

Dave Cheney

unread,
Aug 8, 2017, 3:51:08 AM8/8/17
to golang-nuts
Everyone overused channels and goroutines at first. Why wouldn't you? That's why you probably decided to try Go in the first place.

I have a talk in Singapore a few months ago trying to explore this idea. It sort of went in a different direction, but the conclusion might be interesting for you.

https://dave.cheney.net/paste/concurrency-made-easy.pdf

as....@gmail.com

unread,
Aug 8, 2017, 6:36:21 AM8/8/17
to golang-nuts
Author did a range over channel without select, making cancellation impossible without closing the channel or the process. However, author challenges user to solve cancellation problems with no selection, even saying he awaits for the user to accomplish this. So author will stop waiting when notified, or call them back, to say it's been done. Because it is not possible, we presume author is still blocked waiting on his completion signal, or worse, polling to see any completed the impossible.

In practice, the callback needs to live somewhere in memory. The select statement not so much; it could have provided cancellation by broadcasting through a "done" channel. For one reason or another, the author didn't do this and ranged through the channel instead.

snmed

unread,
Aug 8, 2017, 6:39:42 AM8/8/17
to golang-nuts
Hi Egon

Thank you for your reply, I myself used channel as a semaphore, i'm not sure if that is a appropriate use case for channels.

Anyhow your opionion is very welcome

snmed

unread,
Aug 8, 2017, 6:47:07 AM8/8/17
to golang-nuts
Hi Dave

Thank you for your comment, I will read your talk on my way back home later and I'm sure i get some better insight in go concurrency.
But his argument about better performance of mutex over channels is still valid, maybe you have covered that in your talk, i will see later.

Cheers snmed

Konstantin Khomoutov

unread,
Aug 8, 2017, 7:02:45 AM8/8/17
to snmed, golang-nuts
On Tue, Aug 08, 2017 at 03:39:42AM -0700, snmed wrote:

> > There are trade-offs.
> >
> > Channels are easy to use for simple things, but complicated for complected
> > things.
> >
> > Locking data-structures can easily introduce data-races (see The Little
> > Book of Semaphores http://greenteapress.com/wp/semaphores/).
[...]
> Thank you for your reply, I myself used channel as a semaphore, i'm not
> sure if that is a appropriate use case for channels.
[...]

Channels are quite good to implement simple counting semaphores (those
which have more than a single token / permit to provide): the length of
the channel used in this way is the quantity of permits the semaphore
has, a send to such channel is acquisition of a permit, and receiving
from it returning of the acquired permit back to the semaphore.

Acquisition hence naturally blocks if the semaphore has no free permits
and blocks the requesting goroutine until a free permit becomes
available.

You can easily combine this with a timer to get a counting semaphore
with a timeout.

Haddock

unread,
Aug 8, 2017, 7:35:02 AM8/8/17
to golang-nuts
CSP style concurrency in Go is the killer feature in Go. It makes concurrent programming so much easier. To understand this you need to have done some years of concurrent programming using asynchronous calls, threads, locks, semaphores and all that stuff. I have done that and I can say that CSP style programming in Go with the use of channels makes concurrent programming much much easier. Much easier to get things right from the beginning, much easier to fix things. I have actually spent years fixing other people's and my mistakes causing race conditions and deadlocks. People who have not experienced this have no considerable experience in concurrent programming and don't know what they are talking about.

You have to mention that green threads (aka goroutines) are not preemptive, though. This is what you have to pay for what you get for the ease of concurrent programming using CSP. For many applications this is a very good trade-off. All the server-side applications written in Go confirm this.

Dave Cheney

unread,
Aug 8, 2017, 7:38:21 AM8/8/17
to golang-nuts
Channels are always going to be more expensive than using a lock if all your doing is timing the cost of the lock vs a channel; aka hello world of channels. Channels are there to send values between goroutines representing work to do, in which case that work has to be significantly more than the cost of the transmission otherwise it's easier to just do the work yourself.

Jason Stillwell

unread,
Aug 9, 2017, 4:07:41 AM8/9/17
to golang-nuts
Here's the thing about channels in go. They're a primitive. Just like int is a primitive and string is a primitive. They're not an entire library, or framework. they're just a primitive.

In other languages, currency "tools" are usually provided as some part of a fully featured library, or package, or framework. But not in go. Go provides the primitive, and its up to you to use that to implement your actual concurrency tools.

You might try to store a date in an int. But there are lots of caveats along with doing so. Instead you take primitives like ints and structs and put them together to make a package and set of structures for dealing with Dates. You don't complain that int alone isn't good enough for doing all your date processing.

But a lot of devs see the channel and assume its some high level abstraction built with an API to deal with all your common situations, because thats what they are used to expecting from their other language experience. Its not though. Its just a building block. Build something with it, and then use that something.

On Monday, August 7, 2017 at 11:01:12 PM UTC-7, snmed wrote:

Caleb Doxsey

unread,
Aug 9, 2017, 8:30:38 AM8/9/17
to golang-nuts
Channels are very useful and necessary to really get your program using all the resources at your disposal. Doing that with locks or callbacks is error prone and makes solving some problems all but impossible. Let me give you an example of a pattern we used a few days ago:

We were processing message from a queue, writing some data to Cassandra, and then committing offsets when the work was completed. It was really important for the commits to come out in the same order they came in, so that we never commit an offset when we haven't actually written all the data. (on crash or restart its ok to process the same messages again because the writing is idempotent)

Modeled as a pipeline we had a few stages:

intake -> decode -> encode -> write to cassandra -> commit

The naive approach would be to spin up a bunch of writer goroutines, but then the order of messages to commit would be unpredictable. Instead we created two slices of channels:

ins := make([]chan intakeMessage, options.workers)
outs := make([]chan commitMessage, options.workers)

And spun up goroutines that read from one of the input channels and wrote to the corresponding out channel:

for i := 0; i < options.workers; i++ {
                ins[i] = make(chan intakeMessage, 1)
                outs[i] := make(chan commitMessage, 1)
                go worker(ins[i], outs[i])
}

We then use these slices as a circular buffer and keep track of two pointers, one for the next available in and another for the next remaining out. There are 3 cases:
  1. The slice is empty, in which case we insert at 0 and increment the in counter
  2. The slice is full (all workers are busy), in which case we wait until a result is pushed into the channel at the out counter
  3. We're somewhere in between, in which case we use a select on either the next available in channel or the next remaining out counter
So all the commits come out in the order they came in, we get nice parallelism and there's no blocking or polling.

There is overhead to channels but if you send messages of adequate size you'll barely notice it in real programs. Batch and send slices.

The thing I find remarkable about channels and goroutines is how often the solutions for improving the performance of a Go program are almost exactly the same as the solutions for distributing that program across multiple machines. The patterns really map well to these kinds of problems.

snmed

unread,
Aug 10, 2017, 12:54:10 AM8/10/17
to golang-nuts
Hi Caleb

Your approach seems to me as a reasonable use case for channels and I'm sure it would be a lot complexer if you use a bunch of mutexes.

One part in the article looks a little bit weird to me:
  // ...
  s.mtx.Lock()
  // ...
  s.ch <- val // might block!
  s.mtx.Unlock()
  // ...

My experience with go is limited but until now I have never seen that kind of code, I don't think it is something advanced go users would do or I'm wrong?

Cheers snmed

Jesper Louis Andersen

unread,
Aug 11, 2017, 7:58:54 AM8/11/17
to snmed, golang-nuts
On Tue, Aug 8, 2017 at 8:01 AM snmed <sandro....@gmail.com> wrote:

I stumbled over a nice and very interesting Blog entry "Go channels are bad and you should feel bad" , I would like to hear some opinions about that article
from seasoned go developers. Because I just used go for a couple of months for my private web projects and rarely get in touch with channels.


One way of putting it is that any synchronization/communication primitive will have an overhead in a system. Channels are "fairly expensive" compared to other methods. But if the processing you are doing is going to take orders of magnitude more time than the channel communication, then you can usually benefit from channels having some extra features in them, especially w.r.t. system correctness: they are often easier to program with.

You can create an exaggerated situation: suppose you are in the EU and you decide that you want to distribute your system. You buy a server in Australia. Imagine you have a mythical failure free connection to Australia and you are doing RPC. You are easily looking at 300+ ms roundtrip times. If the task you execute on the Australian server is "add two numbers", then the 300ms overhead is a problem.

But, if the task you are shipping to Australia is an NP-complete route planning you want solved to optimality, you are easily looking at hours of processing time. And then 300ms seems pretty quick!

Channels work much the same, but the window is at the microsecond level. If you protect an operation in the nanosecond scale by a channel, then the channel overhead will dominate. But if you require milliseconds of processing time, then a channel is fairly cheap.

Note that any communication to the outside world is likely to be on the millisecond scale, and that makes channels excellent as a tool to handle an operation which block on some foreign input.

Chris Hopkins

unread,
Aug 11, 2017, 8:22:56 AM8/11/17
to golang-nuts, sandro....@gmail.com
[sorry for the side question but:]
When there is the "channels are expensive" consideration, I assume that is from a latency perspective rather than a throughput perspective.
i.e. it was my understanding that channels had a small overhead on top of a basic lock, but otherwise added very little workload. The microsecond or so of cost you see I understood was *not* due to there being thousands of operations needed to run the channel, but the latency added by the stall, and scheduler overhead.
I also understood that in the case of an uncontested buffered partially full channel*, the cost of a channel was effectively that of checking the head and tail pointers; therefore as close to nothing as makes no difference.

* I know this is a rare case, but I'd also argue it's the only interesting one in data flow applications if you're concerned about the latency as in other cases you will have a contested lock and therefore the overhead of the locking will dominate. (I'm not wanting to worry at the moment about say a lock on a shared data structure (state table?) that is modified infrequently as I'd be surprised if this was done by channels in most applications)

If that makes sense?

Regards

Jesper Louis Andersen

unread,
Aug 12, 2017, 8:35:14 AM8/12/17
to Chris Hopkins, golang-nuts, sandro....@gmail.com
On Fri, Aug 11, 2017 at 2:22 PM Chris Hopkins <cbeho...@gmail.com> wrote:
.... The microsecond or so of cost you see I understood was *not* due to there being thousands of operations needed to run the channel, but the latency added by the stall, and scheduler overhead.
 
One particular case, which many benchmarks end up doing is that they run a single operation through the system which in turn pays all the context switching overhead for that operation. But channels pipeline. If you start running a million operations, then the switching overhead amortizes over the operations if your system is correctly asynchronous and tuned.

I think most message passing languages add some kind of atomics in order to track counters and like stuff without resorting to sending around microscopic messages all the time. 

Michael Jones

unread,
Aug 12, 2017, 5:37:45 PM8/12/17
to Jesper Louis Andersen, Chris Hopkins, golang-nuts, sandro....@gmail.com
snmed,

My disappointment with that blog post is that it does not address the larger issue, which some people here have clarified, but to be clear on the larger issue and the various points raised about channels:

SMALL BENCHMARKS ARE HARD

Benchmarking is harder than it seems, because computers since the IBM 360/85 (1969), the DEC PDP-11/70 (1975), and a others before have memory caches. They can also have multiple CPUs, multiple levels of memory cache, and since 1964's CDC 6000, multiple threads active in a single CPU (the basis of the first NVIDIA GeForce GPU and rediscovered by intel as Jackson Technology, aka SMT, a few years later).

In a world where computers read, write, and compute multiple things at once, it is quite difficult to measure the cost of any single thing. Why? Because if that one thing can be done in some idle part of the computer while other things are happening, then the effective cost is zero. 

Even if you manage to measure that one thing somehow with sufficient scaffolding and after disabling your modern CPU's power saving speed degrader and myriad other processes and performance modulators such as inside the CPU uOp dispatch priority and the like, the problem is, how to understand it and extrapolate from it.

To be clear, if it takes a perfectly measured average of 140 ns +/- 11ns to do something, and you do 100 of them, it will likely not add 100x that time or 100x that variance to your application's actual performance rates. Maybe all 100 of those fit in "empty spots" so the cost is zero. Maybe they conflict with instruction scheduling, bus activity, or cache/VM activity in such a way that they add 100000x that time. 

This is why microbenchmarks are so hard to understand. They are hard to write properly, they are hard to measure in a meaningful way, and they are hard to extrapolate with confidence. (You should do them, but, you should always keep in mind that the application-level, real-world impact may be 0x or 100x that much cost.)

CONCURRENT PROGRAMMING IS HARD

Doing things concurrently generally implies one or more spreading steps where the code widens one thing to multiple things, and one or more gathering steps where the multiple things narrow to fewer things, ultimately to one thing, like knowing when to exit the program. For decades there have been frequent errors in widening, narrowing, and data and device conflicts in the concurrent phase. Code that works for years may suddenly break. Code that looks simple my never work. Natural intuition in such cases often leads one astray.

One solution is to be afraid of concurrency and avoid it. One is to embrace it, but with special armor as if handling hot lava or a pit of vipers. A middle route is to only allow it in such a way that it its tame (Lava in insulated containers, snakes asleep in darkened boxes.) One such mild route--Communicating Sequential Processes--was pioneered by C. A. R. Hoare, the inventor of Quicksort. Per Brinch Hansen has an excellent book about OS construction via the method, and Go is one of CSP's direct decedents. Go's channels, along with select, receive, send, and close operations, are its presence. 

SMALL BENCHMARKS OF CONCURRENCY PRIMITIVES IS VERY HARD

It is hard to measure directly in much the same way it is hard to directly measure curved space-time. Indirect ways are hard too. As above, even when you can measure them, it is hard to understand what that data says in the context of your program or any program other than the test harness. 

This is where that blog post comes in. To paraphrase, "I think some of Go's mild, safe mechanisms lack a feature that I wish for, and not only that, when I use them to emulate some parts of my low-level lava-juggling armor, they are not as fast. Oh no! Yet, I still love Go." Well people see that, seem to miss:

a. Why in the heck would you use high-level magic to emulate low-level tools? In the case of channels, they already use lava juggling and snake charming tools hidden safely inside their implementation.

b. How can you compare performance of high level program structuring elements and low-level viper wrangling tools? Whichever is 'faster' or 'simpler' for the same task is likely a misapplication of one or both.

c. What about the whole notion of making concurrency safe and easy? Experienced people from Tony Hoare to Rob Pike have seen the light about hiding the parts of concurrency that are so often tools of self-destruction in the hands of very good programmers. Why tempt beginners to open that door? Why tempt anyone?

That's what I think when people comment on that post. Sure, new features could be considered. Sure, existing tools can be tweaked toward hardware optimal implementation. Sure, Go provides all the lava and snake tools one could need in the sync package. But unless your well-designed and well-implemented application is too inefficient as it scales from 1 to N CPUs, then why would you think to abandon magic that brings simplicity and correctness to what was formerly a wasteland of failed efforts and inscrutable bugs? ("My plane flies 0.0000001% faster without the weight of my parachute so i leave it behind" is not a well-considered approach.)

How would you know if an application was that inefficient? By benchmarking THE WHOLE APPLICATION rather than an emulation of a low-level concurrency primitive.

Chris,

Channels are not "expensive" it is just that they are not free. I can do 3,000,000 channel send/receive pairs per second on my notebook computer. If each send is a single bit, that's 366kb/second safely and easily sent between communicating processes. If each is a pointer to a 1MB data structure, then that's 3 TB/sec safely and easily sent between communicating processes. It is not likely that any application can do 3 million interesting tasks (build and send web pages, compute market conditions and send buy/sell orders, update databases, etc.) on any computer, much less a four core mobile device on battery power.

Maybe it is possible to do 5x or 20x that many mutex-protected increments of an integer using those viper-handling gloves and body armor. But a computer that is dedicated to updating a single int is questionable, and an application dominated by it is also questionable.

If anything, I'd rather put a sleep in all the sync primitives and force the mental discipline to make the application fast DESPITE artificially slow sync/cond/mutex/wait/... speeds. It is all about high-level design, choice of algorithms and data structures, and similar issues--that's where 100x gains in performance await. 2x on a mutex is just not interesting to me. 

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Michael T. Jones
michae...@gmail.com

as

unread,
Aug 12, 2017, 6:08:58 PM8/12/17
to golang-nuts, jesper.lou...@gmail.com, cbeho...@gmail.com, sandro....@gmail.com
Thank you for writing this informative post. It and explains the issue well and should be shared with others with the same question.

Honestly, Go has made me scared of locks. Every time I think of using one, I realize how bad the actual design of the program is and end up refactoring it. The end result is always better. Channels take care of sync + communication, locks take care of sync only. A process that needs to synchronize but not communicate doesn't make much sense anymore. 
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

snmed

unread,
Aug 18, 2017, 4:32:08 AM8/18/17
to golang-nuts, jesper.lou...@gmail.com, cbeho...@gmail.com
Hi Michael

Thank you very much for your very informative and elaborating post. I never had seen that blog this way, but your post has opened my eyes and now is clear that one should not compare apples with pears.
So the tradeoff is, use concurrency in a safe manner or squezze the last drop performance out of the application, but be aware of shooting in your own leg. So the conclusion is, use channels to get the job done and
if in real use any performance problem pops up, analyze it and verify if the bottleneck is really caused by channels and if it's not a fault in the architecture , right?

Cheers snmed
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Tamás Gulácsi

unread,
Aug 18, 2017, 7:38:00 AM8/18/17
to golang-nuts
No. Use channels to coordinate and send data between goroutines, and other sync primitives to coordinate access to shared resources. Both has its pros and cons, use the best tool for the job.

Michael Jones

unread,
Aug 18, 2017, 9:58:00 AM8/18/17
to Tamás Gulácsi, golang-nuts
yes... everything is good for what it is designed for and less-good for what it is not designed for.

mutex-protected counters are good
channels for data communication are good

neither is a perfect stand in for the other. nothin wrong with channels.

On Fri, Aug 18, 2017 at 4:38 AM, Tamás Gulácsi <tgula...@gmail.com> wrote:
No. Use channels to coordinate and send data between goroutines, and other sync primitives to coordinate access to shared resources. Both has its pros and cons, use the best tool for the job.
--
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+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

John Souvestre

unread,
Aug 18, 2017, 3:05:11 PM8/18/17
to golang-nuts

I think that both of the suggestions below are great.  But I’m left wondering about the Go mantra

 

    Do not communicate by sharing memory. Instead, share memory by communicating.

 

What does it say?  It starts off with communicating as the goal, but doesn’t tell you how to do it.  Then sharing memory is the goal and the solution it provides (communicating) is only right some of the time.

 

Am I missing something?  Should this be replaced?

 

John

    John Souvestre - New Orleans LA

 

From: golan...@googlegroups.com [mailto:golan...@googlegroups.com] On Behalf Of Michael Jones
Sent: 2017 August 18, Fri 08:57
To: Tamás Gulácsi
Cc: golang-nuts
Subject: Re: [go-nuts] Go channels overused and hyped?

 

yes... everything is good for what it is designed for and less-good for what it is not designed for.

 

mutex-protected counters are good

channels for data communication are good

 

neither is a perfect stand in for the other. nothin wrong with channels.

On Fri, Aug 18, 2017 at 4:38 AM, Tamás Gulácsi <tgula...@gmail.com> wrote:

No. Use channels to coordinate and send data between goroutines, and other sync primitives to coordinate access to shared resources. Both has its pros and cons, use the best tool for the job.


--
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...@googlegroups.com.


For more options, visit https://groups.google.com/d/optout.



 

--

Michael T. Jones
michae...@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...@googlegroups.com.

John Souvestre

unread,
Aug 18, 2017, 3:12:33 PM8/18/17
to golang-nuts

P.S.

 

And if you want to reduce it to a one-liner, how about this?

 

    Communicating is better than sharing sometimes, and vice versa.

 

John

    John Souvestre - New Orleans LA

 

From: John Souvestre [mailto:Jo...@Souvestre.com]
Sent: 2017 August 18, Fri 14:03
To: 'golang-nuts'
Subject: RE: [go-nuts] Go channels overused and hyped?

 

I think that both of the suggestions below are great.  But I’m left wondering about the Go mantra

 

    Do not communicate by sharing memory. Instead, share memory by communicating.

 

What does it say?  It starts off with communicating as the goal, but doesn’t tell you how to do it.  Then sharing memory is the goal and the solution it provides (communicating) is only right some of the time.

 

Am I missing something?  Should this be replaced?

 

John

    John Souvestre - New Orleans LA

 

From: golan...@googlegroups.com [mailto:golan...@googlegroups.com] On Behalf Of Michael Jones
Sent: 2017 August 18, Fri 08:57
To: Tamás Gulácsi
Cc: golang-nuts
Subject: Re: [go-nuts] Go channels overused and hyped?

 

yes... everything is good for what it is designed for and less-good for what it is not designed for.

 

mutex-protected counters are good

channels for data communication are good

 

neither is a perfect stand in for the other. nothin wrong with channels.

On Fri, Aug 18, 2017 at 4:38 AM, Tamás Gulácsi <tgula...@gmail.com> wrote:

No. Use channels to coordinate and send data between goroutines, and other sync primitives to coordinate access to shared resources. Both has its pros and cons, use the best tool for the job.


--
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...@googlegroups.com.


For more options, visit https://groups.google.com/d/optout.



 

--

Michael T. Jones
michae...@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...@googlegroups.com.

Ian Lance Taylor

unread,
Aug 18, 2017, 4:14:14 PM8/18/17
to John Souvestre, golang-nuts
On Fri, Aug 18, 2017 at 12:02 PM, John Souvestre <jo...@souvestre.com> wrote:
>
> I think that both of the suggestions below are great. But I’m left
> wondering about the Go mantra
>
>
>
> Do not communicate by sharing memory. Instead, share memory by
> communicating.
>
>
>
> What does it say? It starts off with communicating as the goal, but doesn’t
> tell you how to do it. Then sharing memory is the goal and the solution it
> provides (communicating) is only right some of the time.
>
>
>
> Am I missing something? Should this be replaced?

As I see it, the point of the proverb is to focus on having goroutines
use explicit communication mechanisms, such as channels and mutexes,
to hand control of an area of memory over to another goroutine. An
example of communicating by sharing memory would having one goroutine
poll a memory location that is then changed by a different goroutine.
As a general guideline, prefer explicit communication mechanisms.

Ian

John Souvestre

unread,
Aug 18, 2017, 7:03:53 PM8/18/17
to golang-nuts
Interesting. So you think it is a general safety advisory (which would apply to any language) to use synchronization (ex: mutex or channel) and not a more focused push to use channels? Hmmm... I didn't understand it that way. I thought that "communicate" was a reference to the "C" in CSP. It never crossed my mind that it would mean "use synchronization".

The context of the Go FAQ section which includes the proverb discourages mutexes (with no mention of when they should or should not be used). The two links it provides bolster this and only provide examples using channels.

The wiki article MutexOrChannel starts off with the proverb then immediately follows with "That said, Go does provide traditional locking mechanisms in the sync package." Why the need to say this if the moto was meant to include the sync methods, too?

Everything I recall reading or listening to which references the proverb seems to continue in this theme to avoid locking. Here's a rather explicit one from https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions: " Don’t communicate by sharing memory, share memory by communicating. Our first proverb–don’t mediate access to shared memory with locks and mutexes, instead share that memory by communicating."

Also, in Rob Pike's talk "Go Proverbs" at Gopherfest on 11/18/2015 he talks about this proverb. He defines "sharing memory by communicating" as "passing on a channel the address of a data structure or an object ...".

So I don't think that I'm alone in thinking that the focus of the proverb is to use channels to share memory, rather than any other way. And I find this somewhat wrong and certainly confusing. Am I really alone in this?

John

John Souvestre - New Orleans LA


-----Original Message-----
From: Ian Lance Taylor [mailto:ia...@golang.org]
Sent: 2017 August 18, Fri 15:14
To: John Souvestre
Cc: golang-nuts
Subject: Re: [go-nuts] Go channels overused and hyped?

Matt Harden

unread,
Aug 20, 2017, 1:14:09 PM8/20/17
to John Souvestre, golang-nuts

Mutexes are good for a some low level tasks, and when you must have a shared data structure with no clear owner. When in doubt, and when designing your app, prefer communication over sharing, i.e. channels.


Reply all
Reply to author
Forward
0 new messages