Go in Practice-Manning 2016(读书笔记)

Go in Practice

Getting into Go[编辑]

  1. Noteworthy aspects of Go
    1. 多个返回值
      1. 可以命名返回值??fk func Names() (first string, second string) { first = "Foo" }
    2. A modern standard library
      1. net --> net/http --> html/template --> ...
    3. Concurrency with goroutines and channels
      1. 备注:CSP的概念是否可以大大减少栈空间的占用?同步的函数调用 -> 并发的消息通信 ...
    4. Go the toolchain—more than a language
      1. $ go get ./... 解析代码中的import语句并下载依赖
      2. hello_test.go:
        import "testing"
        func TestXxx(t *testing.T) { ... t.Error("!") }
      3. 1.5+:$ go test -cover
  2. Go in the vast language landscape
    1. C and Go:cgo
    2. Java and Go:Java需要一个分离的单独安装的JVM及其JIT(当然,并发调度模型也不一样?)
    3. Python, PHP and Go
    4. JavaScript, Node.js, and Go
  3. Getting up and running in Go

A solid foundation[编辑]

  1. CLI
    1. 使用flag解析命令行参数:
      1. var name = flag.String("name", "World", "A name to say hello to.")
      2. flag.BoolVar(&spanish, "spanish", false, "Use Spanish language.")
      3. flag.Parse()
      4. flag.VisitAll(func(flag *flag.Flag) { ... fmt.Printf(format, flag.Name, flag.Usage, flag.DefValue) }
    2. launchpad.net/gnuflag ?
    3. github.com/jessevdk/go-flags ?
    4. https://github.com/urfave/cli 一个CLI应用框架?
  2. 处理配置文件
    1. JSON:
      decoder := json.NewDecoder(file) //file, _ := os.Open("conf.json")
      conf := configuration{} //自定义的struct,这里似乎没有加``标注?
      err := decoder.Decode(&conf)
    2. https://github.com/coreos/etcd 分布式配置和服务发现
    3. YAML: github.com/kylelemons/go-gypsy/yaml
      config, err := yaml.ReadFile("conf.yaml")
      fmt.Println(config.Get("path"))
    4. INI:gopkg.in/gcfg.v1
      err := gcfg.ReadFileInto(&config, "conf.ini") //注意,ini有个section分组的概念(无非就是个嵌套struct)
    5. 环境变量
      1. Twelve-factor apps(PaaS最佳实践?)
      2. os.Getenv("PORT")
  3. Working with real-world web servers
    1. 优雅地关闭?github.com/braintree/manners
      1. main:
        ch := make(chan os.Signal)
        signal.Notify(ch, os.Interrupt, os.Kill)
        go listenForShutdown(ch)
        manners.ListenAndServe(":8080", handler) //Hook API;
      2. func listenForShutdown(ch <-chan os.Signal) {
        <-ch
        manners.Close() //允许当前的request处理完成(但是这里还是有个问题:假如遇到pending io怎么办?)
    2. Routing web requests
      1. pr := newPathResolver() //path包?==> path.Match(pattern, req.Method + " " + req.URL.Path)
        pr.Add("GET /hello", hello)
        pr.Add("* /goodbye/*", goodbye)
        • 缺点:匹配foo/bar/baz需要写foo/*/*,而/goodbye/*不能匹配/goodbye
      2. 利用regexp匹配url:略
      3. Faster routing (without the work)
        1. github.com/julienschmidt/httprouter 大小写敏感、可处理/../
        2. github.com/gorilla/mux
        3. github.com/bmizerany/pat Sinatra风格,如/user/:name

Concurrency in Go[编辑]

  1. sync.WaitGroup
    1. wg.Add(1) ==> go func() { ... wg.Done() }() ==> wg.Wait()
  2. $ go run --race race.go *.txt
    1. 利用sync.Mutex保护对共享数据的并发访问
  3. select模式:
    done := time.After(30 * time.Second)
    select { //还可以在外面再for{}包装一下?
    ...
    case <-done: fmt.Println("Timed out")
  4. a closed channel always returns the channel’s nil value //对chan bool就是false?
    1. 用一个额外的channel来代表当前channel已关闭?每个channel相当于一个单向的msg通道?
  5. using a channel as a lock //这种情况下当前goroutine既写也读;
    1. lock := make(chan bool, 1)

处理errors和panics[编辑]

  1. An error indicates that a particular task couldn't be completed successfully.
    1. panic indicates that a severe event occurred, probably as a result of a programmer error.(内核BUG_ON~)
  2. func Concat(parts ...string) (string, error) {
    if len(parts)==0 { return "", errors.New("No strings supplied") }
  3. args := os.Args[1:]
    if result, err := Concat(args...); err != nil { ... } else ... //注意,if的scope包括else分支
  4. 包级别的error变量:如io.EOF
  5. panic(errors.New("Something bad happened."))
    1. defer func() { if err := recover(); err != nil { ... } }()
      • 既然是推迟执行的函数,那么怎么表达“re-try”的逻辑呢?交给更上一层来处理?
  6. !注意:defer闭包无法引用后面声明的变量(这跟JS的函数作用域不一样)
  7. A panic on a goroutine can't jump to the call stack of the function that initiated the goroutine.

调试和测试[编辑]

  1. logger := log.New(logfile, "logprefix ", log.LstdFlags|log.Lshortfile)
  2. 把log重定向到网络端口:
    1. nc -lk 1902
    2. conn, err := net.Dial("tcp", "localhost:1902")
      defer conn.Close()
      logger := log.New(conn, "example ", flog.Ldate | log.Lshortfile)
  3. 处理back-pressure:本地缓存
    1. 改用UDP:conn, err := net.DialTimeout("udp", "localhost:1902", timeout) //但仍然会有数据丢失、传输失序的问题
    2. 3rd包:https://github.com/Sirupsen/logrus https://github.com/golang/glog
  4. 输出到syslog
    1. logger, err := syslog.NewLogger(priority, flags)
    2. Logging to a remote syslog(略)
  5. Accessing stack traces
    1. runtime/debug包:debug.PrintStack() => runtime.Stack(buf, false)
  6. Generative testing:testing/quick //自动生成测试数据?
  7. Using performance tests and benchmarks
    1. b *testing.B ?=> 循环迭代到b.N点?

HTML与email模板模式[编辑]

  1. ?<a href="/user?id={ {.Id | urlquery}}"> //{{会当作mediawiki格式的模板命令,下面省略只用1对{}表示
  2. {.Date | dateFormat "Jan 2, 2006"} // http://golang.org/pkg/time/#Time.Format
  3. var t = template.Must(template.ParseFiles("templates/simple.html")) //包变量
  4. err := t.Execute(&bytes_Buffer, params)
  5. 嵌入子模板:{template "header.html" .}
  6. 模板继承*
    1. {define "base"} ... {end}
    2. 1.6+:{block "styles" .} ... {end}
    3. temp := template.Must(template.ParseFiles("base.html", "user.html")) //?

Serving and receiving assets and forms[编辑]

  1. http.ListenAndServe(":8080", http.FileServer(http.Dir("./files")))
    1. 也可以针对单独的文件:http.ServeFile(res, req, "./files/readme.txt")
    2. 去除url请求中的path前缀:
      1. handler := http.StripPrefix("/static/", http.FileServer(dir))
      2. http.Handle("/static/", handler)
  2. github.com/Masterminds/go-fileserver 定制的错误页?(居然是专为这本书写的?节省pdf页数?靠)
  3. 将静态文件缓存到内存:
    1. r := bytes.NewReader(b.Bytes()) //io.ReadSeeker类型?
      ==> http.ServeContent(res, req, req.URL.Path, v.modTime, v.content)
  4. RWMutex
  5. groupcache?提供跨server的共享内存缓存
  6. 将二进制资源打包进binary:github.com/GeertJohan/go.rice
    1. box := rice.MustFindBox("../files/")
    2. httpbox := box.HTTPBox()
    3. ==> $ rice embed-go && go build(不错,这个工具看上去很神奇)
  7. name := r.FormValue("name") //获取表单请求参数
  8. FormValue、PostFormValue(不包含url查询参数):获取第一个值
  9. 迭代多个值:
    1. err := r.ParseMultipartForm(maxMemory)
    2. for k, v := range r.PostForm["names"] { ... }
  10. 处理文件上传
    1. f, h, err := r.FormFile("file") //f是解析完成的文件内容(在内存里?)还是说等实际read时JIT地解析?
      类型:multipart.File, *multipart.FileHeader
    2. defer f.Close()
    3. out, err := os.Create("/tmp/" + h.Filename)
    4. defer out.Close()
    5. io.Copy(out, f)
  11. Uploading multiple files(多个文件上传)
    1. <input type="file" name="files" id="files" multiple> //Wtf,这我还没注意到,一个input元素就可以上传多个文件
    2. 服务器端:
      err := r.ParseMultipartForm(16 << 20)
      data := r.MultipartForm
      files := data.File["files"]
      for _, fh := range files {
      f, err := fh.Open()
      defer f.Close()
      ... //下略
  12. 验证上传文件的mime类型(略)
  13. Working with raw multipart data
    1. *multipart.Reader:r.MultipartReader
  14. 增量保存上传的文件:?(看起来只是为了节省服务器端内存,不是断点续传)

Web服务[编辑]

  1. 客户端:
    1. c := &http.Client{Timeout: time.Second}
    2. ➥ res, err := c.Get("http://goinpracticebook.com")
  2. 检测超时错误:
    1. case *url.Error:
      if err, ok := err.Err.(net.Error); ok && err.Timeout() { ...
    2. case *net.OpError:
      if err.Timeout() { ...
  3. 超时后自动resume:
    1. req.Header.Set("Range", "bytes="+strconv.FormatInt(file.Stat().Size(), 10)+"-") //Size为什么是一个函数呢?
  4. Parsing and mapping JSON:略
  5. Versioning REST APIs:无聊!

Using the cloud[编辑]

  1. 交叉编译:$ GOOS=windows GOARCH=386 go build
  2. 运行时监控:
    1. m := &runtime.MemStats{} ==> r := runtime.NumGoroutine(); runtime.ReadMemStats(m) //总感觉这里的代码有点怪异?

云服务之间的通信[编辑]

  1. 重用连接:
    tr := &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: pool},
    DisableCompression: true,
    Dial: (&net.Dialer{
    Timeout: 30 * time.Second,
    KeepAlive: 30 * time.Second,
    }).Dial,
  2. HTTP/2 Pipelining
    1. 不要defer r.Body.Close()
  3. Faster JSON marshal and unmarshal(去掉了反射,因此速度更快)
    1. $ go get -u github.com/ugorji/go/codec/codecgen
    2. $ codecgen -o user_generated.go user.go //预先定义好struct...
  4. Moving beyond REST
    1. $ go get -u github.com/golang/protobuf/protoc-gen-go
    2. $ protoc -I=. --go_out=. ./user.proto
    3. gRPC:www.grpc.io

反射与代码生成[编辑]

  1. name, type, value
  2. 判断interface{}是否是特定类型:2'
    1. _, ok := v.(fmt.Stringer)
    2. func implements(concrete interface{}, target interface{}) bool {
      iface := reflect.TypeOf(target).Elem()
      v := reflect.ValueOf(concrete)
      t := v.Type()
      if t.Implements(iface) { return true }
  3. Structs, tags, and annotations
    1. FirstName string `json:"first" xml:"firstName,attr"`
    2. ...
  4. Generating Go code with Go code
    1. 基于html模板类似语法?元编程?扯淡
    2. 基于go/ast?还是要编译的吧?
Summary Go in Practice guides you through 70 real-world techniques in key areas like package management, microservice communication, and more. Following a cookbook-style Problem/Solution/Discussion format, this practical handbook builds on the foundational concepts of the Go language and introduces specific strategies you can use in your day-to-day applications. Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from Manning Publications. About the Technology Go may be the perfect systems language. Built with simplicity, concurrency, and modern applications in mind, Go provides the core tool set for rapidly building web, cloud, and systems applications. If you know a language like Java or C#, it's easy to get started with Go; the trick is finding the practical dirt-under-the-fingernails techniques that you need to build production-ready code. About the Book Go in Practice guides you through dozens of real-world techniques in key areas. Following a cookbook-style Problem/Solution/Discussion format, this practical handbook builds on the foundational concepts of the Go language and introduces specific strategies you can use in your day-to-day applications. You'll learn techniques for building web services, using Go in the cloud, testing and debugging, routing, network applications, and much more. After finishing this book, you will be ready to build sophisticated cloud-native Go applications. What's Inside Dozens of specific, practical Golang techniques Using Go for devops and cloudops Writing RESTful web services and microservices Practical web dev techniques About the Reader Written for experienced developers who have already started exploring Go and want to use it effectively in a production setting. About the Authors Matt Farina is a software architect at Deis. Matt Butcher is a Principal Engineer in the Advanced Technology Group at Hewlett Packard Enterprise. They are both authors, speakers, and regular open source contributors. Table of Contents Part 1 Background and fundamentals Chapter 1 Getting into Go Chapter 2 A solid foundation Chapter 3 Concurrency in Go Part 2 Well-rounded applications Chapter 4 Handling errors and panics Chapter 5 Debugging and testing Part 3 An interface for your applications Chapter 6 HTML and email template patterns Chapter 7 Serving and receiving assets and forms Chapter 8 Working with web services Part 4 Taking your applications to the cloud Chapter 9 Using the cloud Chapter 10 Communication between cloud services Chapter 11 Reflection and code generation
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值