Live data from Hacker News

The Beauty of Concurrency in Go

pragprog.com

81–90 of 95 posts

Re: The Beauty of Concurrency in Go

#81

This article and many like suffer from one of my huge pet-peeves, absolutely terrible coding conventions. I am a person who likes to scan articles, I'm busy and generally make a read now, read later, read never decision. The code from first scan was unreadable, short 1 character variable names, "why is there a hardcoded date marked 2006.01.02-15.04.05 there??", etc. Readable code takes a little more time - but it's w…

> "why is there a hardcoded date marked 2006.01.02-15.04.05 there??"

That's actually how datetime patterns are defined in Go. I shit you not.

Re: The Beauty of Concurrency in Go

#82
post #74
post #24

> > Notably, if a package is included but not used, Go treats this as an error and enforces removing unused declarations A good illustration that the Go designers didn't think their ideas through. This is a real pain in the butt when you are writing code and regularly commenting in and out sections of code while you are testing things. And every time you do this, you need to remove or restore the imports. And since G…

Jesus Jumping Blue Christ, why is it that every time Golang comes up in any type of discussion, there's always someone out there who complains that Go is horrible because it doesn't implement their favorite pet non-mainstream language features, which is obviously because the Go designers were inexperienced newbies with only 50 years of experience designing groundbreaking software, and therefore lacked your deep insig…

I usually chalk it up to armchair quarterbacking.

Re: The Beauty of Concurrency in Go

#83
post #32

Earlier quoted context omitted.

It is easy to accidentally share state between goroutines. For example, we wish to print out elements of a list: values := []string{"a", "b", "c"} for _, v := range values { go fmt.Println(v) } Each of these goroutines shares the same variable v, so this code contains a serious race condition.

It may be easy, but it's not that easy. values := []string{"a", "b", "c"} for _, v := range values { go func(){fmt.Println(v);}() } Does have a race condition. values := []string{"a", "b", "c"} for _, v := range values { go func(s string){fmt.Println(s);}(v) } Does not have a race condition.

You're still shaving v here, we can just see from the snipped that the shared v isn't used inside the anon function. But I suspect what the GP meant by "easy" is not having to think about this sort of thing. Your solution is good when you know you need to do this, but it can't even happen in Erlang so it's not a "gotcha" to watch out for.

Re: The Beauty of Concurrency in Go

#84
post #22

Earlier quoted context omitted.

> I know I can use "chan struct{}" to avoid any storage, but I think " I disagree. struct{}{} tells me that the value isn't important. Whenever I use map as a set, rather than a key-value store I use map[string]struct{} (say), rather than map[string]bool. Then I am forced to use the double assignment to check for membership of the set. And that's exactly what I want. I'm able to make my intent more obvious in the cod…

> I dislike using booleans instead of empty structs in the same way Eh? If you have `map[keyType]bool`, then a key lookup is simply the set membership function. If a key exists, it returns true. Otherwise, false. That certainly doesn't seem analogous to abusing integers as booleans...

How do you work out how many elements are in your set?

Re: The Beauty of Concurrency in Go

#85
post #32

Earlier quoted context omitted.

It may be easy, but it's not that easy. values := []string{"a", "b", "c"} for _, v := range values { go func(){fmt.Println(v);}() } Does have a race condition. values := []string{"a", "b", "c"} for _, v := range values { go func(s string){fmt.Println(s);}(v) } Does not have a race condition.

You're still shaving v here, we can just see from the snipped that the shared v isn't used inside the anon function. But I suspect what the GP meant by "easy" is not having to think about this sort of thing. Your solution is good when you know you need to do this, but it can't even happen in Erlang so it's not a "gotcha" to watch out for.

Sharing v isn't the problem. The problem occurs when v is evaluated.

The parent's post has no race condition, as v is evaluated before the goroutine starts.

The top example of my post has a race condition because there is no guarantee when v will be evaluated wrt to the loop.

The bottom example has no race condition because v is evaluated on every iteration and assigned to s, which is used by the goroutine at some point afterwards.

Re: The Beauty of Concurrency in Go

#86
post #84

Earlier quoted context omitted.

> I dislike using booleans instead of empty structs in the same way Eh? If you have `map[keyType]bool`, then a key lookup is simply the set membership function. If a key exists, it returns true. Otherwise, false. That certainly doesn't seem analogous to abusing integers as booleans...

How do you work out how many elements are in your set?

With the built-in len function.

Re: The Beauty of Concurrency in Go

#87
post #85

Earlier quoted context omitted.

You're still shaving v here, we can just see from the snipped that the shared v isn't used inside the anon function. But I suspect what the GP meant by "easy" is not having to think about this sort of thing. Your solution is good when you know you need to do this, but it can't even happen in Erlang so it's not a "gotcha" to watch out for.

Sharing v isn't the problem. The problem occurs when v is evaluated. The parent's post has no race condition, as v is evaluated before the goroutine starts. The top example of my post has a race condition because there is no guarantee when v will be evaluated wrt to the loop. The bottom example has no race condition because v is evaluated on every iteration and assigned to s, which is used by the goroutine at some po…

My point still stands: to fix this, you have to realize that (a) v could be shared here and (b) that sharing could be a problem. I suspect the first time most newbies get hit with a race condition here they're going to be beyond baffled.

Re: The Beauty of Concurrency in Go

#88
post #67
post #36

Earlier quoted context omitted.

False. The Go designers have explained many times why they made unused imports an error. In particular unused dependencies slow down compilation. There's even a FAQ: http://golang.org/doc/faq#unused_variables_and_imports . A trivial workaround to silence the compiler errors during development is to use blank identifiers ( http://golang.org/doc/effective_go.html#blank_unused ). I use them all the time. You may disagre…

Maybe they did think it through, but their conclusion reveals some inexperience. It's impractical on many levels. Thus the need for kludgy solutions like blank identifiers. I'd rather see a strict mode or some other type of compiler flag.

Impractical for you. I particularly enjoy the rigidity of the compiler.

Re: The Beauty of Concurrency in Go

#89
post #80

Earlier quoted context omitted.

People develop at different speeds. For me, anything like this that slows me down and interrupts my flow with 3-4 seconds of "click on the error message and add a one-line comment" is incredibly annoying. Development has several modes. One mode is "hacking", just hashing out what you want until it works and is elegant enough as a solution, perhaps changing your mind frequently when you see how it works in practice. A…

> Development has several modes. One mode is "hacking", > just hashing out what you want until it works and is > elegant enough as a solution, perhaps changing your mind > frequently when you see how it works in practice. > Another is "polishing", carefully annotating, cleaning > up, documenting, burning off loose threads, making sure > the test coverage is top notch, etc. > > The problem is that Go's compile-time st…

Without measuring how productive we (you and I) are as programmers, such a qualitative judgement is largely meaningless.

Anecdotally, I have had colleagues who always plan ahead meticulously, using pen and paper and diagrams and plenty of note-taking before ever writing a single line of code, and the first line of code is often a test. And yet those people were terrible programmers. They take a long time to produce working code, and it's often deeply flawed. They will spend half a day or an entire day trying to hunt down a bug that I found to be trivially obvious even without knowing the codebase. Meticulousness does not imply quality.

Re: The Beauty of Concurrency in Go

#90
post #47

Earlier quoted context omitted.

Go doesn't "force" you to use one method of concurrency. It has more than one (you can do erlang-style share-nothing style or Java/C++ style of using mutexes to protect shared state from concurrent access). I know nothing about Closure so it's possible it has more features but it's not necessarily a good thing. Is the complexity of 4 different solutions worth it? (by "it" I mean: a programmer has to learn all of them…

So why use Go instead of node.js? You can probably take that reasoning and substitute "Go" for "Clojure", and "node.js" for "Go". Go people would probably object that the things that Go adds, and that node.js lacks, aren't just window dressing -- sure, there are situations where a node.js-style fast event loop that avoids blocking operations is all you need, but there are also situations where you want something more…

Static typing and availability of AOT compilation?
Post reply on HN