A few notable changes in Go 1.6

Source: Internet
Author: User
Tags benchmark gopher
This is a creation in Article, where the information may have evolved or changed.

In the early morning of February 18, 2016 in Beijing time, after go 1.5 released six months, go 1.6 officially release. The change to go 1.6 is small compared to go 1.5 's "big change" (mostly go), which is also related to go 1.6 's dev cycle being too short. But the go Community has paid much attention to the release, which is even more enthusiastic than go 1.5. At the initiative of Dave Cheney, Gophers held the Go 1.6 Release party around the world. Go Core team also opened a ama–ask Me anything,robpike, Russ Cox (RSC), Bradfitz and other go big gods in Reddit, to the majority of Gophers in 24hour within the question of a must answer.

Let's take a look at what changes in Go 1.6 deserve our attention. But before we talk about change, let's start with a mouth. Go 1.6 unchanged, that is, the Go Language language specification, still keep go 1 compatible unchanged. It is expected that we will not see any changes to go language specification in the next few stable release releases.

First, CGO

The CGO change is:
1, defined between go code and C code transfer pointer, that is, C code and go garbage collector coexistence of rules and restriction;
2, in the runtime added to the violation of the inspection, check the switch and intensity by godebug=cgocheck=1[0,2] control. 1 is the default, 0 is a close check, and 2 is a more thorough but costly check.

The proposal was proposed by Ian Lance Taylor. It is broadly divided into two situations:

(a) When Go calls C code

When Go calls C code, go pass to C code The go pointer refers to the go memory can not contain any point to go memory of the pointer. We are divided into several situations to explore:

1. Pass a pointer to the struct

//cgo1_struct.gopackage main/*#include 
  
   
    
   struct Foo{    int a;    int *p;};void plusOne(struct Foo *f) {    (f->a)++;    *(f->p)++;}*/import "C"import "unsafe"import "fmt"func main() {    f := &C.struct_Foo{}    f.a = 5    f.p = (*C.int)((unsafe.Pointer)(new(int)))    //f.p = &f.a    C.plusOne(f)    fmt.Println(int(f.a))}
  
   

As you can see from the Cgo1_struct.go code, go code passes a pointer f to C code that points to go memory (go Assignment), but F points to the go memory with a pointer p pointing to another go memory:new (int), Let's run this code:

$go run cgo1_struct.go# command-line-arguments./cgo1_struct.go:12:2: warning: expression result unused [-Wunused-value]panic: runtime error: cgo argument has Go pointer to Go pointergoroutine 1 [running]:panic(0x4068400, 0xc82000a110)    /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main.main()    /Users/tony/test/go/go16/cgo/cgo1_struct.go:24 +0xb9exit status 2

The code appears panic and prompts: "CGO argument has go pointer to go pointer". Our code violates the CGO pointer pass rule, even if f.p points to the struct's own memory, such as F.P = &F.A.

2. Pass a pointer to the struct field

As stated in the rules, if you pass a pointer to a struct field, "Go memory" refers to the memory occupied by the field, even if there are other field points in the struct that point to other Go memory matter:

//cgo1_structfield.gopackage main/*#include 
  
   
    
   struct Foo{    int a;    int *p;};void plusOne(int *i) {    (*i)++;}*/import "C"import (    "fmt"    "unsafe")func main() {    f := &C.struct_Foo{}    f.a = 5    f.p = (*C.int)((unsafe.Pointer)(new(int)))    C.plusOne(&f.a)    fmt.Println(int(f.a))}
  
   

Operation result of the above program:

$go run cgo1_structfield.go6

3. Pass a pointer to element in the slice or array

Unlike transitive struct field, when passing a pointer to an element in a slice or array, the range of go memory to consider is not just this element, but the entire array or the underlying behind the entire slice The area of memory occupied by the array to ensure that no pointers to any go memory are included in this area. Let's look at the code example:

//cgo1_sliceelem.gopackage main/*#include 
  
   
    
   void plusOne(int **i) {    (**i)++;}*/import "C"import (    "fmt"    "unsafe")func main() {    sl := make([]*int, 5)    var a int = 5    sl[1] = &a    C.plusOne((**C.int)((unsafe.Pointer)(&sl[0])))    fmt.Println(sl[0])}
  
   

From this code, we see that we are passing the address of the first element of slice, which is &sl[0]. We did not assign a value to Sl[0], but Sl[1] was assigned to another Go memory address (&a), and when we passed &sl[0] to PlusOne, the result was as follows:

$go run cgo1_sliceelem.gopanic: runtime error: cgo argument has Go pointer to Go pointergoroutine 1 [running]:panic(0x40dbac0, 0xc8200621d0)    /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main.main()    /Users/tony/test/go/go16/cgo/cgo1_sliceelem.go:19 +0xe4exit status 2

The runtime panic because of a violation of the rules.

(b) C when calling go code

1. The go function called by C cannot return a pointer to the memory of Go allocation

Let's look at the following example:

Cgo2_1.go

package main// extern int* goAdd(int, int);//// static int cAdd(int a, int b) {//     int *i = goAdd(a, b);//     return *i;// }import "C"import "fmt"//export goAddfunc goAdd(a, b C.int) *C.int {    c := a + b    return &c}func main() {    var a, b int = 5, 6    i := C.cAdd(C.int(a), C.int(b))    fmt.Println(int(i))}

As you can see: Goadd this go function returns a pointer to the memory (&c) of Go allocation. Run the above code with the following results:

$go run cgo2_1.gopanic: runtime error: cgo result has Go pointergoroutine 1 [running]:panic(0x40dba40, 0xc82006e1c0)    /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main._cgoexpwrap_872b2f2e7532_goAdd.func1(0xc820049d98)    command-line-arguments/_obj/_cgo_gotypes.go:64 +0x3amain._cgoexpwrap_872b2f2e7532_goAdd(0x600000005, 0xc82006e19c)    command-line-arguments/_obj/_cgo_gotypes.go:66 +0x89main._Cfunc_cAdd(0x600000005, 0x0)    command-line-arguments/_obj/_cgo_gotypes.go:45 +0x41main.main()    /Users/tony/test/go/go16/cgo/cgo2_1.go:20 +0x35exit status 2

2. Go code cannot store pointers to go allocated memory in memory allocated by C

The following example simulates this situation:

//cgo2_2.gopackage main// #include 
  
   
    
   // extern void goFoo(int**);//// static void cFoo() {//     int **p = malloc(sizeof(int*));//     goFoo(p);// }import "C"//export goFoofunc goFoo(p **C.int) {    *p = new(C.int)}func main() {    C.cFoo()}
  
   

However, for this example, the default godebug=cgocheck=1 bias is not a check problem. Let's change Godebug=cgocheck to =2:

$GODEBUG=cgocheck=2 go run cgo2_2.gowrite of Go pointer 0xc82000a0f8 to non-Go memory 0x4300000fatal error: Go pointer stored into non-Go memoryruntime stack:runtime.throw(0x4089800, 0x24)    /Users/tony/.bin/go16/src/runtime/panic.go:530 +0x90runtime.cgoCheckWriteBarrier.func1()    /Users/tony/.bin/go16/src/runtime/cgocheck.go:44 +0xaeruntime.systemstack(0x7fff5fbff8c0)    /Users/tony/.bin/go16/src/runtime/asm_amd64.s:291 +0x79runtime.mstart()    /Users/tony/.bin/go16/src/runtime/proc.go:1048... ...goroutine 17 [syscall, locked to thread]:runtime.goexit()    /Users/tony/.bin/go16/src/runtime/asm_amd64.s:1998 +0x1exit status 2

Indeed runtime panic:write of Go pointer 0xc82000a0f8 to non-go memory 0x4300000

Second, HTTP/2

HTTP/2 was originally a Bradfitz maintenance x project, previously located in the GOLANG.ORG/X/NET/HTTP2 package, and go 1.6 was not stitched into the Go standard library net/http package. And when you use HTTPS, the client and server side automatically default to using the HTTP/2 protocol.

The difference between the HTTP/2 and the http1.x protocol is that it is a binary protocol, not a text protocol, and performance is greatly improved. HTTP/2 standards have been published, presumably in the next few years will be a big line.

HTTP/2 more complex, here do not repeat, the follow-up maybe will write a separate go and HTTP2 article description.

Third, Templates

Because I do not develop web,templates, I often use very little. Here's a superficial talk about the templates increase of two feature

Trim whitespace characters

The white space characters of Go templates include: spaces, horizontal tab, carriage return, and line feed. These blanks are especially difficult to deal with when editing templates on a daily basis, and because of the "obsessive compulsive disorder" of beatiful format and code readabliity, this is a lot of time.

Go 1.6 provides {{-and-}} to help you remove whitespace characters before and after the action. The following example is a good illustration of this:

//trimwhitespace.gopackage mainimport (    "log"    "os"    "text/template")var items = []string{"one", "two", "three"}func tmplbefore15() {    var t = template.Must(template.New("tmpl").Parse(`    
  
   
   
    {{range . }}
  • {{.}}
  • {{end }}
`)) err := t.Execute(os.Stdout, items) if err != nil { log.Println("executing template:", err) }}func tmplaftergo16() { var t = template.Must(template.New("tmpl").Parse(`
    {{range . -}}
  • {{.}}
  • {{end -}}
`)) err := t.Execute(os.Stdout, items) if err != nil { log.Println("executing template:", err) }}func main() { tmplbefore15() tmplaftergo16()}

This example runs the result:

$go run trimwhitespace.go    
  
   
   
  • one
  • two
  • three
  • one
  • two
  • three

Block action

The block action provides a capability to override the existing template form at run time.

  Package Mainimport ("Log" "OS" "Text/template") var items = []string{"One", "one", "three"}var Overrid    Eitemlist = ' {define ' list '-}} 
   
   
    {{range.-}}
  • {{.}}
  • {{end-}}
{{end}} ' var Tmpl = ' Items: {{block ' list '-}}
    {{range.}}
  • {{.}}
  • {{End}}
{{end}} ' var t *template. Templatefunc init () {t = template. Must (template. New ("Tmpl"). Parse (Tmpl))}func tmplbeforeoverride () {err: = T.execute (OS). Stdout, items) if err! = Nil {log. PRINTLN ("Executing Template:", err)}}func tmplafteroverride () {t = template. Must (T.parse (overrideitemlist)) Err: = T.execute (OS. Stdout, items) if err! = Nil {log. PRINTLN ("Executing Template:", err)}}func main () {FMT. Println ("before override:") Tmplbeforeoverride () fmt. Println ("after override:") Tmplafteroverride ()}

In the original template Tmpl, a block action defines an inline template anchor named list and an initial definition. Later run time through the Re-parse overrideitemlist to achieve the purpose of modifying template display form.

The above code outputs the result:

$go run blockaction.gobefore override:    Items:    
  
   
   
  • one
  • two
  • three
after override: Items:
  • one
  • two
  • three

Four, Runtime

Reduce GC latency for large memory usage

The Go 1.5.x is traded at a lower throughput cost for GC latency below 10ms. But for Go 1.5, the official benchmark figure, the memory heap size is about 20G. Once more than 20g,latency will exceed 10ms, it may grow linearly.
In Go 1.6, the official given benchmark figure in the memory heap size at 200G, GC latency can still stabilize at 10ms, when the heap size is less than 20G, latency to 6ms or even smaller.

Panic Info

Prior to Go 1.6, once the program exits in panic mode, runtime will print all the goroutine stack information:

$go versiongo version go1.5.2 darwin/amd64[ ~/test/go/go16/runtime]$go run panic.gopanic: runtime error: invalid memory address or nil pointer dereference[signal 0xb code=0x1 addr=0x0 pc=0x20d5]goroutine 1 [running]:main.main()    /Users/tony/test/go/go16/runtime/panic.go:19 +0x95goroutine 4 [select (no cases)]:main.main.func1(0x8200f40f0)    /Users/tony/test/go/go16/runtime/panic.go:13 +0x26created by main.main    /Users/tony/test/go/go16/runtime/panic.go:14 +0x72... ...

When go 1.6, go only prints the stack information of the goroutine that is being running, so it is the real culprit that is most likely to cause panic:

go 1.6:$go run panic.gopanic: runtime error: invalid memory address or nil pointer dereference[signal 0xb code=0x1 addr=0x0 pc=0x20d5]goroutine 1 [running]:panic(0x61e80, 0x8200ee0c0)    /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main.main()    /Users/tony/test/go/go16/runtime/panic.go:19 +0x95exit status 2

Map Race Detect

The Go Native map type is Goroutine-unsafe, which has long caused a lot of gophers trouble. The go 1.6 runtime adds detection of concurrent access maps to reduce the mental burden of gopher when they use map.

Here is a sample program borrowed from Francesc Campoy in the latest issue of "The State of Go":

package mainimport "sync"func main() {    const workers = 100    var wg sync.WaitGroup    wg.Add(workers)    m := map[int]int{}    for i := 1; i <= workers; i++ {        go func(i int) {            for j := 0; j < i; j++ {                m[i]++            }            wg.Done()        }(i)    }    wg.Wait()}

Execution Result:

$ go run map.gofatal error: concurrent map writesfatal error: concurrent map writes... ...

Here in the dual-core i5 Mac Air under the pro-test, found that when workers=2,3,4 can not detect race. When workers >= 5 o'clock can be detected.

V. Other

Handwriting parser replaces YACC-generated parser

This change is transparent to the gopher, but it is very important to go compiler itself.

Robert Riesemer commits the handwriting parser before the go 1.6 code freezing to replace the parser generated by YACC. Robpike on AMA gave some reasons for changing the parser:
1, Go compiler can maintain a YACC tool less, so more cleaner;
2, handwriting parser in performance can be a little bit faster.

Go 1.6 in Go15vendorexperiment will be turned on by default

The go15vendorexperiment in Go 1.6 will be turned on by default, according to the plan when vendor was introduced in Go 1.5. This obviously leads to some incompatibilities: that is, if your code does not use the vendor mechanism before, there is a vendor directory in the directory organization. The solution for Go Core team is to delete the vendor directory or rename it.

Whether the remaining issues are resolved

After the release of Go 1.5, there were two problems, until go 1.5.3 release has not been resolved, then go 1.6 solve it? Let's check it out.

Internal problems

The specifics of this issue can be found in the issue 12217 I submitted on Go GitHub, where I submitted a validation environment code for the issue in my experiments, and this time we use Go 1.6 to see if the internal problem still exists:

$cd $GOPATH/src/github.com/bigwhite/experiments/go15-internal-issue-12217$cd otherpkg/$go build main.gopackage main    imports github.com/bigwhite/experiments/go15-internal-issue-12217/mypkg/internal/foo: use of internal package not allowed

This time go compiler gave the error, not the same as the previous version of the successful compilation passed. It seems that the problem is fix dropped.

The question of whether the vendor mechanism works outside Gopath

Let's set up an experimental environment first:

$tree.└── testvendor    └── src        └── proj1            ├── main.go            └── vendor                └── github.com                    └── bigwhite                        └── foo                            └── foolib.go

Enter Proj1,build Main.go

go build main.gomain.go:3:8: cannot find package "github.com/bigwhite/foo" in any of:    /Users/tony/.bin/go16/src/github.com/bigwhite/foo (from $GOROOT)    /Users/tony/Test/GoToolsProjects/src/github.com/bigwhite/foo (from $GOPATH)

The go 1.6 compiler did not pay attention to the vendor directory under the same path, and build failed.

After we set the Gopath=xxx/testvendor, we will build:

$export GOPATH=~/Test/go/go16/others/testvendor$go run main.goHello from temp vendor

This time compile run OK.

From this, Go 1.6 vendor is still not effective outside gopath.

Vi. Summary

Go 1.6 Standard library minor changes are still a lot of, in Go 1.6 Release notes can savor.

The compilation speed of Go 1.6, the running performance of the compiled program and the go 1.5.x are almost no different.

In addition this article realizes the environment as follows:

go version go1.6 darwin/amd64Darwin tonydeair-2.lan 13.1.0 Darwin Kernel Version 13.1.0: Thu Jan 16 19:40:37 PST 2014; root:xnu-2422.90.20~2/RELEASE_X86_64 x86_64

The experiment code can be downloaded here.

, Bigwhite. All rights reserved.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.