From fcfed1479e0fd96cc8c5fb21b4b8b590267491f1 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 23 Jan 2012 08:39:53 -0800 Subject: [PATCH] FAQ: update to Go 1. R=adg, rsc, r CC=golang-dev https://golang.org/cl/5562051 --- doc/go_faq.html | 142 ++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 65 deletions(-) diff --git a/doc/go_faq.html b/doc/go_faq.html index 6a8199fd94..33e5cde41a 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -190,10 +190,11 @@ easier to understand what happens when things combine.

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 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.

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.

@@ -541,7 +544,7 @@ interface I by attempting an assignment:
 type T struct{}
-var _ I = T{}
+var _ I = T{}   // Verify that T implements I.
 

@@ -557,8 +560,8 @@ For example:

 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

-Why don't maps allow structs and arrays as keys?

+Why don't maps allow slices as keys?

-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. +

+

Why are maps, slices, and channels references while arrays are values?

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

-Why am I confused by the way my closures behave as goroutines?

+What happens with closures running as goroutines?

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 = 1
 
has 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 -- 2.50.0