Sunday, January 31, 2016

GoLang Misc



https://sourabhbajaj.com/mac-setup/Go/README.html
$ brew update
$ brew install golang
export GOPATH=$HOME/go-workspace # don't forget to change your path correctly!
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$GOROOT/bin^

https://medium.freecodecamp.org/writing-command-line-applications-in-go-2bc8c0ace79d

https://michaelheap.com/golang-how-to-go-get-private-repos/
Fortunately, as go get uses git, you can change your .gitconfig to force it to use SSH.
$ git config --global url."git@github.com:".insteadOf "https://github.com/"
$ cat ~/.gitconfig
[url "git@github.com:"]
    insteadOf = https://github.com/
Here, we say use git@github.com any time you’d use https://github.com. This works for everything, not just go get. It just has the nice side effect of using your SSH key any time you run go get too.
go env
https://stackoverflow.com/questions/12514037/golang-installing-packages-in-a-local-directory
You might want to consider using Go Version Manager (gvm).
Apart from switching between Go versions easily, it also lets you switch between pkgsets("workspaces").
First you create a set
gvm pkgset create myproject
and then you use it
gvm pkgset use myproject
Works like a charm.
https://groups.google.com/forum/#!topic/golang-nuts/WJJuQJOM-nQ
export GOPATH=$HOME/src/golang/go3p 
vi ~/.bash_profile
export PATH=$PATH:/usr/local/go/bin
go get -u 
https://marketplace.visualstudio.com/items?itemName=lukehoban.Go
First, you will need to install Visual Studio Code 0.10. In the command palette (cmd-shift-p) select Install Extension and choose Go.

In a terminal window with the GOPATH environment variable set to the GOPATH you want to work on, launch code. Open your GOPATH folder or any subfolder you want to work on, then open a .go file to start editing. You should seeAnalysis Tools Missing in the bottom right, clicking this will offer to install all of the Go tooling needed for the extension to support its full feature set. See the Tools section below for more details.
Note: Users may want to consider turning Auto Save on in Visual Studio Code ("files.autoSave": "afterDelay") when using this extension. Many of the Go tools work only on saved files, and error reporting will be more interactive with Auto Save turned on. If you do turn Auto Save on, you may also want to turn format-on-save off ("go.formatOnSave": "false"), so that it is not triggered while typing.

To use the debugger, you must currently manually install delve. See the Installation Instructions for full details. On OS X it requires creating a self-signed cert to sign the dlv binary.
go get -u github.com/newhook/go-symbols

To run go program: go run test.go

http://www.tutorialspoint.com/go/go_basic_syntax.htm
package main

import "fmt"

func main() {
   fmt.Println("Hello, World!")
}
http://marcio.io/2015/07/supercharging-atom-editor-for-go-development/

go version
debug
https://github.com/mailgun/godebug
go get github.com/mailgun/godebug
https://atom.io/packages/go-debug
A go debugger for atom using delve.
GoEclipse

https://blog.cloudflare.com/go-has-a-debugger-and-its-awesome/

https://github.com/derekparker/delve/blob/master/Documentation/installation/osx/install.md
brew install go-delve/delve/delve
xcode-select --install
DevToolsSecurity -enable

Visual Code Studio
            "env": {
                "NODE_ENV": "development"
            },

    "args": [
        "hello!"
    ]
go run helloworld.go go build helloworld.go ./helloworld go get gopl.io/ch1/helloworld func, var, const, and type os.Args[0], is the name of the command itself for i := 1; i < len(os.Args); i++ { s += sep + os.Args[i] sep = " " } The := symbol is part of a short variable declaration, a statement that declares one or more variables and gives them appropriate types based on the initializer values. for initialization; condition; post { // zero or more statements } Go does not permit unused local variables for _, arg := range os.Args[1:] { s += sep + arg sep = " " } s := "" it may be used only within a function, not for package-level variables. var s string var s = "" var s string = "" A simpler and more efficient solution would be to use the Join function from the strings package: fmt.Println(strings.Join(os.Args[1:], " ")) counts := make(map[string]int) input := bufio.NewScanner(os.Stdin) for input.Scan() { counts[input.Text()]++ } // NOTE: ignoring potential errors from input.Err() for line, n := range counts { if n > 1 { fmt.Printf("%d\t%s\n", n, line) } } for _, arg := range files { f, err := os.Open(arg) if err != nil { fmt.Fprintf(os.Stderr, "dup2: %v\n", err) continue } countLines(f, counts) f.Close() } func countLines(f *os.File, counts map[string]int) { input := bufio.NewScanner(f) for input.Scan() { counts[input.Text()]++ } // NOTE: ignoring potential errors from input.Err() } "io/ioutil" "math" "math/rand" var palette = []color.Color{color.White, color.Black} anim := gif.GIF{LoopCount: nframes} "net/http" resp, err := http.Get(url) b, err := ioutil.ReadAll(resp.Body) resp.Body.Close() "time" start := time.Now() ch := make(chan string) for _, url := range os.Args[1:] { go fetch(url, ch) // start a goroutine } for range os.Args[1:] { fmt.Println(<-ch) // receive from channel ch } fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds()) func fetch(url string, ch chan<- string) { start := time.Now() resp, err := http.Get(url) if err != nil { ch <- fmt.Sprint(err) // send to channel ch return } nbytes, err := io.Copy(ioutil.Discard, resp.Body) resp.Body.Close() // don't leak resources if err != nil { ch <- fmt.Sprintf("while reading %s: %v", url, err) return } secs := time.Since(start).Seconds() ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url) } A goroutine is a concurrent function execution. A channel is a communication mechanism that allows one goroutine to pass values of a specified type to another goroutine. The io.Copy function reads the body of the response and discards it by writing to the ioutil.Discard output stream. When one goroutine attempts a send or receive on a channel, it blocks until another goroutine attempts the corresponding receive or send operation, at which point the value is transferred and both goroutines proceed. In this example, each fetch sends a value (ch <- expression) on the channel ch, and main receives all of them (<-ch). "log" "net/http" http.HandleFunc("/", handler) // each request calls handler log.Fatal(http.ListenAndServe("localhost:8000", nil)) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path) } "sync" var mu sync.Mutex http.HandleFunc("/count", counter) mu.Lock() fmt.Fprintf(w, "Count %d\n", count) mu.Unlock() if err := r.ParseForm(); err != nil { log.Print(err) } Named types type Point struct { X, Y int } var p Point Pointers are explicitly visible. The & operator yields the address of a variable, and the * operator retrieves the variable that the pointer refers to, but there is no pointer arithmetic. https://golang.org/pkg https://godoc.org go doc http.ListenAndServe var name type = expression var b, f, s = true, 2.3, "four" // bool, float64, string i, j = j, i // swap values of i and j := is a declaration, whereas = is an assignment A short variable declaration must declare at least one new variable p := &x // p, of type *int, points to x *p = 2 // equivalent to x = 2 "flag" var n = flag.Bool("n", false, "omit trailing newline") var sep = flag.String("s", " ", "separator") fmt.Print(strings.Join(flag.Args(), *sep)) if !*n { fmt.Println() } The variables sep and n are pointers to the flag variables, which must be accessed indirectly as *sep and *n. When the program is run, it must call flag.Parse before the flags are used, to update the flag variables from their default values. The non-flag arguments are available from flag.Args() as a slice of strings. If flag.Parse encounters an error, it prints a usage message and calls os.Exit(2) to terminate the program. p := new(int) // p, of type *int, points to an unnamed int variable fmt.Println(*p) // "0" TUPLE ASSIGNMENT All of the right-hand side expressions are evaluated before any of the variables are updated. medals := []string{"gold", "silver", "bronze"} A type declaration defines a new named type that has the same underlying type as an existing type. The named type provides a way to separate different and perhaps incompatible uses of the underlying type so that they can’t be mixed unintentionally. type Celsius float64 func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } exported identifiers start with an upper-case letter. Only one file in each package should have a package doc comment. Extensive doc comments are often placed in a file of their own, conventionally called doc.go. By default, the short name is the package name—tempconv in this case—but an import declaration may specify an alternative name to avoid a conflict. It is an error to import a package and then not refer to it. Better still, use the golang.org/x/tools/cmd/goimports tool, which automatically inserts and removes packages from the import declaration as necessary; Such init functions can’t be called or referenced, but otherwise they are normal functions. basic types, aggregate types, reference types, and interface types int8, int16, int32, and int64, and corresponding unsigned versions uint8, uint16, uint32, and uint64. byte, float64 should be preferred for most purposes because float32 computations accumulate error rapidly

var a [3]int             // array of 3 integers
fmt.Println(a[len(a)-1]) // print the last element, a[2]
var q [3]int = [3]int{1, 2, 3}
q := [...]int{1, 2, 3}
The size of an array is part of its type, so [3]int and [4]int are different types.

r := [...]int{99: -1}
symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
When a function is called, a copy of each argument value is assigned to the corresponding parameter variable, so the function receives a copy, not the original.
func zero(ptr *[32]byte) {
    for i := range ptr {
        ptr[i] = 0
    }
}
Slices represent variable-length sequences whose elements all have the same type. A slice has three components: a pointer, a length, and a capacity.
months := [...]string{1: "January", /* ... */, 12: "December"}

Since a slice contains a pointer to an element of an array, passing a slice to a function permits the function to modify the underlying array elements.
func reverse(s []int) {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
}
a := [...]int{0, 1, 2, 3, 4, 5}
reverse(a[:])
Unlike arrays, slices are not comparable, so we cannot use == to test whether two slices contain the same elements
runes = append(runes, r)

top := stack[len(stack)-1] // top of stack
stack = stack[:len(stack)-1] // pop
func remove(slice []int, i int) []int {
    copy(slice[i:], slice[i+1:])
    return slice[:len(slice)-1]
}
ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}
sort.Strings(names)
names := make([]string, 0, len(ages))
age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0. */ }
if age, ok := ages["bob"]; !ok { /* ... */ }

func equal(x, y map[string]int) bool {
    if len(x) != len(y) {
        return false
    }
    for k, xv := range x {
        if yv, ok := y[k]; !ok || yv != xv {
            return false
        }
    }
    return true
}
var graph = make(map[string]map[string]bool)

func addEdge(from, to string) {
    edges := graph[from]
    if edges == nil {
        edges = make(map[string]bool)
        graph[from] = edges
    }
    edges[to] = true
}

func hasEdge(from, to string) bool {
    return graph[from][to]
}
The name of a struct field is exported if it begins with a capital letter;
type tree struct {
    value       int
    left, right *tree
}

// Sort sorts values in place.
func Sort(values []int) {
    var root *tree
    for _, v := range values {
        root = add(root, v)
    }
    appendValues(values[:0], root)
}

// appendValues appends the elements of t to values in order
// and returns the resulting slice.
func appendValues(values []int, t *tree) []int {
    if t != nil {
        values = appendValues(values, t.left)
        values = append(values, t.value)
        values = appendValues(values, t.right)
    }
    return values
}

func add(t *tree, value int) *tree {
    if t == nil {
        // Equivalent to return &tree{value: value}.
        t = new(tree)
        t.value = value
        return t
    }
    if value < t.value {
        t.left = add(t.left, value)
    } else {
        t.right = add(t.right, value)
    }
    return t
}
p := Point{1, 2}
anim := gif.GIF{LoopCount: nframes}
type Circle struct {
    Point
    Radius int
}
w = Wheel{Circle{Point{8, 8}, 5}, 20}
the outer struct type gains not just the fields of the embedded type but its methods too.

Year   int  `json:"released"`
Color  bool `json:"color,omitempty"`
data, err := json.Marshal(movies)
data, err := json.MarshalIndent(movies, "", "    ")
var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {}
"encoding/json"
q := url.QueryEscape(strings.Join(terms, " "))
resp, err := http.Get(IssuesURL + "?q=" + q)
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    resp.Body.Close()
    return nil, err
}
resp.Body.Close()
Title:  {{.Title | printf "%.64s"}}
Age:    {{.CreatedAt | daysAgo}} days
report, err := template.New("report").
    Funcs(template.FuncMap{"daysAgo": daysAgo}).
    Parse(templ)
var report = template.Must(template.New("issuelist").
    Funcs(template.FuncMap{"daysAgo": daysAgo}).
    Parse(templ))
var data struct {
    A string        // untrusted plain text
    B template.HTML // trusted HTML
}
func first(x int, _ int) int { return x }

deadline := time.Now().Add(timeout)
for tries := 0; time.Now().Before(deadline); tries++ {
    _, err := http.Head(url)
    if err == nil {
        return nil // success
    }
    log.Printf("server not responding (%s); retrying...", err)
    time.Sleep(time.Second << uint(tries)) // exponential back-off
}
The zero value of a function type is nil. Calling a nil function value causes a panic:

func squares() func() int {
    var x int
    return func() int {
        x++
        return x * x
    }
}
function values are not just code but can have state. The anonymous inner function can access and update the local variables of the enclosing function.
var prereqs = map[string][]string{ }
func topoSort(m map[string][]string) []string {
    var order []string
    seen := make(map[string]bool)
    var visitAll func(items []string)

    visitAll = func(items []string) {
        for _, item := range items {
            if !seen[item] {
                seen[item] = true
                visitAll(m[item])
                order = append(order, item)
            }
        }
    }

    var keys []string
    for key := range m {
        keys = append(keys, key)
    }

    sort.Strings(keys)
    visitAll(keys)
    return order
}
var rmdirs []func()
for _, d := range tempDirs() {
    dir := d               // NOTE: necessary!
    os.MkdirAll(dir, 0755) // creates parent directories too
    rmdirs = append(rmdirs, func() {
        os.RemoveAll(dir)
    })
}

// ...do some work...

for _, rmdir := range rmdirs {
    rmdir() // clean up
}
the actual call is deferred until the function that contains the defer statement has finished.

func bigSlowOperation() {
    defer trace("bigSlowOperation")() // don't forget the extra parentheses
    // ...lots of work...
    time.Sleep(10 * time.Second) // simulate slow operation by sleeping
}

func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() { log.Printf("exit %s (%s)", msg, time.Since(start)) }
}
var httpSchemeRE = regexp.MustCompile(`^https?:`) // "http:" or "https:"
func printStack() {
    var buf [4096]byte
    n := runtime.Stack(buf[:], false)
    os.Stdout.Write(buf[:n])
}
func Parse(input string) (s *Syntax, err error) {
    defer func() {
        if p := recover(); p != nil {
            err = fmt.Errorf("internal error: %v", p)
        }
    }()
    // ...parser...
}
A method is declared with a variant of the ordinary function declaration in which an extra parameter appears before the function name. The parameter attaches the function to the type of that parameter.

func (p Point) Distance(q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y)
}
convention dictates that if any method of Point has a pointer receiver, then all methods of Point should have a pointer receiver, even ones that don’t strictly need it.

Learning Go Web Development
always run go fmt before shipping or pushing your code.
go get command reads the master branch of the remote repository.
fmt.Println will produce desired content at the console level, Fprintln allows you to direct output to any writer.
http.ListenAndServe(PORT, http.FileServer(http.Dir("/var/www")))
gorilla/mux: This is intended to create flexible routes that allow regular expressions to dictate available variables for routers.

"github.com/gorilla/mux"
"net/http"
func pageHandler(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  pageID := vars["id"]
  fileName := "files/" + pageID + ".html"
  http.ServeFile(w,r,fileName)
}
rtr := mux.NewRouter()
rtr.HandleFunc("/pages/{id:[0-9]+}",pageHandler)
http.Handle("/",rtr)
err := os.Stat(fileName)
  if err != nil {
    fileName = "files/404.html"
  }

http.ServeFile(w,r,fileName)
"database/sql"
_ "github.com/go-sql-driver/mysql"

It's also often used when a developer plans to use a library, but hasn't yet. By prepending the package this way, it allows the import declaration to stay without causing a compiler error.

var database *sql.DB
type Page struct {
  Title   string
  Content string
  Date    string
}
dbConn := fmt.Sprintf("%s:%s@tcp(%s)/%s", DBUser, DBPass, DBHost, DBDbase)
db, err := sql.Open("mysql", dbConn)
thisPage := Page{}
err := database.QueryRow("SELECT page_title,page_content,page_date FROM pages WHERE id=?", pageID).Scan(&thisPage.Title, &thisPage.Content, &thisPage.Date)
routes.HandleFunc("/page/{guid:[0-9a-zA\\-]+}", ServePage)
http.Error(w, http.StatusText(404), http.StatusNotFound)
tpl, err := template.New("mine").Parse(`<h1>{{.Title}}</h1>`)
t, _ := template.ParseFiles("templates/blog.html")
t.Execute(w, thisPage)

RawContent string
Content    template.HTML
err := database.QueryRow("SELECT page_title,page_content,page_date FROM pages WHERE page_guid=?", pageGUID).Scan(&thisPage.Title, &thisPage.RawContent, &thisPage.Date)
thisPage.Content = template.HTML(thisPage.RawContent)
http.Redirect(w, r, "/home", 301)

var Pages = []Page{}
defer pages.Close()
for pages.Next() {
  thisPage := Page{}
  pages.Scan(&thisPage.Title, &thisPage.RawContent, &thisPage.Date)
  thisPage.Content = template.HTML(thisPage.RawContent)
  Pages = append(Pages, thisPage)
}
t, _ := template.ParseFiles("templates/index.html")
t.Execute(w, Pages)

{{range .}}
  <div><a href="!">{{.Title}}</a></div>
  <div>{{.Content}}</div>
  <div>{{.Date}}</div>
{{end}}
we can essentially share a method between the application and the template.
routes.HandleFunc("/api/pages/{guid:[0-9a-zA\\-]+}", APIPage).
  Methods("GET").
  Schemes("https")
APIOutput, err := json.Marshal(thisPage)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, thisPage)
a good policy is to keep the most recent URL canonical and deprecate to explicit version URLs.

certificates, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
tlsConf := tls.Config{Certificates: []tls.Certificate{certificates}}
tls.Listen("tcp", PORT, &tlsConf)

type JSONResponse struct {
  Fields map[string]string
}

err := r.ParseForm()
name := r.FormValue("name")
res, err := database.Exec("INSERT INTO comments SET comment_name=?, comment_email=?, comment_text=?", name, email, comments)
id, err := res.LastInsertId()
var resp JSONResponse
resp.Fields["id"] = string(id)
resp.Fields["added"] =  commentAddedBool
jsonResp, _ := json.Marshal(resp)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, jsonResp)

routes.HandleFunc("/api/comments/{id:[\\w\\d\\-]+}", APICommentPut).
  Methods("PUT")

http://blog.panic.so/share/2015/09/17/Golang%E5%A6%82%E4%BD%95%E5%B9%B6%E5%8F%91/

Threads, Processes and Green Threads

在linux中,进程和线程的都由task_struct对象来表示,区别在于signal handler,以及线程共享了虚拟内存空间等,尽管这些区别可能会让线程在创建和context switch的时候更加轻松些,但其实看起来没有明显的区别。
当然进程并不只是task_struct对象,它是可执行代码和所操作数据的集合,是一个动态的实体,随着可执行代码的执行而动态变化。进程同时包含了程序计数器,CPU内的各个寄存器以及存放临时变量的程序栈等。所以我们大概可以想象出进程在进行context switch时要进行的操作。
kernel负责对进程(线程)进行调度,系统会把不同的进程运行在不同的CPU上来提升CPU的利用率。当一个进程阻塞时,CPU会被调度执行其他的进程。调度的目的是提高系统的在单位时间内执行的任务吞吐量,降低任务从可执行到执行结束的时间,使进程占用的资源更加合理,系统对于进程和线程的调度是无差别的。
green threads可以理解是用户态线程,它运行在用户空间中。也就是我们在程序层面实现了类似操作系统线程这样的概念,通常这个实现逻辑会简单许多。
green threads可以带来什么?最显而易见的是:在不支持线程的操作系统上,我们依旧可以在语言层面上实现green threads。其次操作系统提供的线程是一个大而全的对象,而对于用户程序来说,诸多功能是冗余的,因此green threads的构造可以更简单,调度策略也更加简单。goroutine可以理解为是一种green threads,它建立在系统线程之上,所以go程序可以并行执行成千上万个goroutine。

Goroutine

green threads的实现通常有三种模型:多个green threads运行在同一个kernel thread上,优点是context switch的速度快,但是只能运行在一个核上;一个green thread对应一个kernel thread,优点是可以利用多核,但是由于绑定关系context swtich会更耗时。
goroutine使用了第三种模型,也就是多个green threads运行在多个kernel threads上,既可以快速的进行context switch又可以很好的利用多核。显然缺点是调度策略会因此变得非常复杂。goroutine的实现使用work stealing算法,定义了MPG三个角色,分别代表kernel threads,processor和goroutine。
image
P也可以理解为context,我们设置的GOMAXPROCS就是指的P的数量。P负责完成对G和M的调度。P维护了一个deque来存放可执行的G,进行调度时切换当前执行的G,从deque顶部取出下一个G继续执行。当G进行syscall阻塞时,不仅需要切换G,M也需要进行切换来保证P能够继续执行后面的G,当阻塞的G-M对就绪时会被重新调度执行。同时当P维护的所有的G执行结束后,会从别的P的deque的steal一半的G放入自己的deque中执行,这也就是为什么叫做work steal算法。

Non-Blocking I/O

Go提供了同步阻塞的IO模型,但Go底层并不没有使用kernel提供的同步阻塞I/O模型。green threads通常在实现的时候会避免使用同步阻塞的syscall,原因在于当kernel threads阻塞时,需要创建新的线程来保证green threads能够继续执行,代价非常高。所以Go在底层使用非阻塞I/O的模型来避免M阻塞。
当goroutine尝试进行I/O操作而IO未就绪时,syscall返回error,当前执行的G设置为阻塞,而M可以被调度继续执行其他的G,这样就不需要再去创建新的M。当然只是Non-Blocking I/O还不够,Go实现了netpoller来进行I/O的多路复用,在linux下通过epoll实现,epoll提供了同步阻塞的多路复用I/O模型。当G阻塞到I/O时,将fd注册到epoll实例中进行epoll_wait,就绪的fd回调通知给阻塞的G,G重新设置为就绪状态等待调度继续执行,这种实现使得Go在进行高并发的网络通信时变得非常强大,相比于php-fpm的多进程模型,Go Http Server使用很少的线程运行非常多的goroutine,而尽可能的让每一个线程都忙碌起来,这样提高了CPU的利用率,减少了系统进行context switch的开销,从而hold住更大的并发量级。



Go 语言在工业上有非常多的应用,包括分布式系统和云计算平台等。而 Go 语言并行性能高、部署方便和简单便捷等特性令其在一些应用上超过了 Python


Go 编程无法成功扩展的一大原因在于错误检查和错误处理代码的编写。总体来看,Go 编程代码检查错误太多,但处理这些错误的代码却非常不足(下文将给出解释)。该设计草案旨在通过引入比当前惯用的「赋值和 if 语句」(assignment-and-if-statement)组合更轻量级的错误检查语法来解决这个问题。
Go 极其地快。其性能与 Java 或 C++相似。在我们的使用中,Go 一般比 Python 要快 30 倍
原因 2:语言性能很重要
Python 非常棒,但是其在序列化/去序列化、排序和聚合中表现欠佳。我们经常会遇到这样的问题:Cassandra 用时 1ms 检索了数据,Python 却需要 10ms 将其转化成对象。

其唯一的创新之处是 goroutines 和通道。Goroutines 是 Go 面向线程的轻量级方法,而通道是 goroutines 之间通信的优先方式。

创建 Goroutines 的成本很低,只需几千个字节的额外内存,正由于此,才使得同时运行数百个甚至数千个 goroutines 成为可能。你可以借助通道实现 goroutines 之间的通信。Go 运行时间可以表示所有的复杂性。Goroutines 以及基于通道的并发性方法使其非常容易使用所有可用的 CPU 内核,并处理并发的 IO——所有不带有复杂的开发。相较于 Python/Java,在一个 goroutine 上运行一个函数需要最小的样板代码。你只需使用关键词「go」添加函数调用:
原因 5:快速的编译时间

原因 8:GOFMT,强制代码格式

Gofmt 是一种强大的命令行功能,内建在 Go 的编译器中来规定代码的格式。从功能上看,它类似于 Python 的 autopep8。格式一致很重要,但实际的格式标准并不总是非常重要。Gofmt 用一种官方的形式规格代码,避免了不必要的讨论。

原因 9:gRPC 和 Protocol Buffers

Go 语言对 protocol buffers 和 gRPC 有一流的支持。这两个工具能一起友好地工作以构建需要通过 RPC 进行通信的微服务器(microservices)。我们只需要写一个清单(manifest)就能定义 RPC 调用发生的情况和参数,然后从该清单将自动生成服务器和客户端代码。这样产生代码不仅快速,同时网络占用也非常少。



Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts