From: Rob Pike
Yes. There are now several Go programs deployed in
-production inside Google. For instance, the server behind
-http://golang.org is a Go program;
-in fact it's just the
Concurrency and multi-threaded programming have a reputation
-for difficulty. We believe the problem is due partly to complex
+for difficulty. We believe this is due partly to complex
designs such as pthreads and partly to overemphasis on low-level details
such as mutexes, condition variables, and memory barriers.
Higher-level interfaces enable much simpler code, even if there are still
@@ -433,7 +434,9 @@ we believe is easy to use and in some ways more general. There are
also ways to embed types in other types to provide something
analogous—but not identical—to subclassing.
Moreover, methods in Go are more general than in C++ or Java:
-they can be defined for any sort of data, not just structs.
+they can be defined for any sort of data, even built-in types such
+as plain, “unboxed” integers.
+They are not restricted to structs (classes).
@@ -446,7 +449,7 @@ How do I get dynamic dispatch of methods?
The only way to have dynamically dispatched methods is through an
-interface. Methods on structs or other types are always resolved statically.
+interface. Methods on a struct or any other concrete type are always resolved statically.
@@ -557,8 +560,8 @@ For example:
godoc
-document server running in a production configuration.
+production inside Google. A public example is the server behind
+http://golang.org.
+It's just the godoc
+document server running in a production configuration on
+Google App Engine.
@@ -362,7 +363,7 @@ because we feel it's sometimes worth trying a different approach.
Why build concurrency on the ideas of CSP?
@@ -541,7 +544,7 @@ interface
I
by attempting an assignment:
type T struct{}
-var _ I = T{}
+var _ I = T{} // Verify that T implements I.
type Fooer interface {
- Foo()
- ImplementsFooer()
+ Foo()
+ ImplementsFooer()
}
@@ -590,7 +593,7 @@ itself with another value:
type Equaler interface {
- Equal(Equaler) bool
+ Equal(Equaler) bool
}
@@ -673,7 +676,7 @@ slice. This example converts a slice of int
to a slice of
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
- s[i] = v
+ s[i] = v
}
@@ -750,17 +753,22 @@ to write one but it will not be as convenient syntactically; this seems a reason
-Map lookup requires an equality operator, which structs and arrays do not implement. +Map lookup requires an equality operator, which slices do not implement. They don't implement equality because equality is not well defined on such types; there are multiple considerations involving shallow vs. deep comparison, pointer vs. -value comparison, how to deal with recursive structures, and so on. -We may revisit this issue—and implementing equality for structs and arrays +value comparison, how to deal with recursive types, and so on. +We may revisit this issue—and implementing equality for slices will not invalidate any existing programs—but without a clear idea of what equality of structs and arrays should mean, it was simpler to leave it out for now.
++In Go 1, equality is defined for structs and arrays, so such +types can be used as map keys, but slices still do not have a definition of equality. +
+@@ -833,7 +841,7 @@ value makes a copy of the pointer, but not the data it points to.
-Map and slice values behave like pointers; they are descriptors that +Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to. Copying an interface value makes a copy of the thing stored in the interface value. If the interface @@ -954,6 +962,8 @@ local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. +Also, if a local variable is very large, it might make more sense +to store it on the heap rather than the stack.
@@ -993,10 +1003,8 @@ See the Share Memory By Communicating code Why doesn't my multi-goroutine program use multiple CPUs?
-Under the gc compilers you must set GOMAXPROCS
to allow the
-run-time support to utilise more than one OS thread. Under gccgo
an OS
-thread will be created for each goroutine, and GOMAXPROCS
is
-effectively equal to the number of running goroutines.
+You must set GOMAXPROCS
to allow the
+run-time support to utilize more than one OS thread.
@@ -1010,10 +1018,6 @@ documentation.)
Why does using GOMAXPROCS
> 1 sometimes make my program
slower?
-
-(This is specific to the gc compilers. See above.) -
-It depends on the nature of your program. Programs that contain several goroutines that spend a lot of time @@ -1067,7 +1071,7 @@ This is almost never the desired behavior.
Some confusion may arise when using closures with concurrency. @@ -1076,29 +1080,30 @@ Consider the following program:
func main() { - done := make(chan bool) - - values := []string{ "a", "b", "c" } - for _, v := range values { - go func() { - fmt.Println(v) - done <- true - }() - } - - // wait for all goroutines to complete before exiting - for _ = range values { - <-done - } + done := make(chan bool) + + values := []string{ "a", "b", "c" } + for _, v := range values { + go func() { + fmt.Println(v) + done <- true + }() + } + + // wait for all goroutines to complete before exiting + for _ = range values { + <-done + } }
One might mistakenly expect to see a, b, c
as the output.
What you'll probably see instead is c, c, c
. This is because
-each closure shares the same variable v
. Each closure prints the
-value of v
at the time fmt.Println
is executed,
-rather than the value of v
when the goroutine was launched.
+each iteration of the loop uses the same instance of the variable v
, so
+each closure shares that single variable. When the closure runs, it prints the
+value of v
at the time fmt.Println
is executed,
+but v
may have been modified since the goroutine was launched.
@@ -1107,12 +1112,12 @@ could modify the inner loop to read:
- for _, v := range values { - go func(u string) { - fmt.Println(u) - done <- true - }(v) - } + for _, v := range values { + go func(u string) { + fmt.Println(u) + done <- true + }(v) + }
@@ -1133,9 +1138,9 @@ result:
if expr { - n = trueVal + n = trueVal } else { - n = falseVal + n = falseVal }@@ -1327,9 +1332,9 @@ import "unused" var _ = unused.Item // TODO: Delete before committing! func main() { - debugData := debug.Profile() - _ = debugData // Used only during debugging. - .... + debugData := debug.Profile() + _ = debugData // Used only during debugging. + .... } @@ -1343,10 +1348,12 @@ One of Go's design goals is to approach the performance of C for comparable programs, yet on some benchmarks it does quite poorly, including several in test/bench. The slowest depend on libraries for which versions of comparable performance are not available in Go. -For instance, pidigits depends on a multi-precision math package, and the C +For instance, pidigits.go +depends on a multi-precision math package, and the C versions, unlike Go's, use GMP (which is written in optimized assembler). -Benchmarks that depend on regular expressions (regex-dna, for instance) are +Benchmarks that depend on regular expressions +(regex-dna.go, for instance) are essentially comparing Go's native regexp package to mature, highly optimized regular expression libraries like PCRE. @@ -1354,7 +1361,8 @@ mature, highly optimized regular expression libraries like PCRE.
Benchmark games are won by extensive tuning and the Go versions of most of the benchmarks need attention. If you measure comparable C -and Go programs (reverse-complement is one example), you'll see the two +and Go programs +(reverse-complement.go is one example), you'll see the two languages are much closer in raw performance than this suite would indicate.
@@ -1362,8 +1370,8 @@ indicate.Still, there is room for improvement. The compilers are good but could be better, many libraries need major performance work, and the garbage collector -isn't fast enough yet (even if it were, taking care not to generate unnecessary -garbage can have a huge effect). +isn't fast enough yet. (Even if it were, taking care not to generate unnecessary +garbage can have a huge effect.)
@@ -1398,13 +1406,13 @@ prefix *
for pointers is an exception that proves the rule). In C,
the declaration
- int* a, b; + int* a, b;
declares a
to be a pointer but not b
; in Go
- var a, b *int + var a, b *int
declares both to be pointers. This is clearer and more regular.
@@ -1412,11 +1420,11 @@ Also, the :=
short declaration form argues that a full variable
declaration should present the same order as :=
so
- var a uint64 = 1 + var a uint64 = 1has the same effect as
- a := uint64(1) + a := uint64(1)
Parsing is also simplified by having a distinct grammar for types that @@ -1495,8 +1503,7 @@ memory management. We feel it's critical to eliminate that programmer overhead, and advances in garbage collection technology in the last few years give us confidence that we can implement it with low enough overhead and no significant -latency. (The current implementation is a plain mark-and-sweep -collector but a replacement is in the works.) +latency.
@@ -1515,6 +1522,11 @@ Finally, concurrency aside, garbage collection makes interfaces simpler because they don't need to specify how memory is managed across them.
++The current implementation is a parallel mark-and-sweep +collector but a future version might take a different approach. +
+On the topic of performance, keep in mind that Go gives the programmer considerable control over memory layout and allocation, much more than