go 食用指南

Golang高效食用秘籍

一、关于构建

1.1 go环境变量

$ go env // 查看go 的环境变量

其中

  • GOROOT 是golang 的安装路径
  • GOPATH 是go命令依赖的一个环境变量
    • 可以理解为工作目录

1.2 go的整体开发目录

go_project     // go_project为GOPATH目录
  -- bin
     -- myApp1  // 编译生成
     -- myApp2  // 编译生成
     -- myApp3  // 编译生成
  -- pkg
  -- src
     -- myApp1     // project1
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp2     // project2
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp3     // project3
        -- models
        -- controllers
        -- others
        -- main.go 

变量声明

var x string = "hello world"
var x [5]int  //数组
var x [5]float64
i := 1
x := [5]float64{99, 44, 22, 11, 1}
x := [5]float64{
  98,
  93,
  77,
  82,
  83,
}
x := [4]float64{
  98,
  93,
  77,
  82,
  // 83,
}

打印

package main
import "fmt"

func main() {
    fmt.Println("hello world")
}

格式化输出

title := fmt.Sprintf("已采集%d个药草, 还需要%d个完成任务", progress, target)

循环

for 

基本类型

注释

/* */
//

标识符


* 和 操作符

  • ‘*’ 代表指针

    • func one(xPtr *int) {
          *xPtr = 1
      }
      xPtr := new(int) 表示初始化int类型的一个指针
      

structs

type Circle struct{
    x, y, r float64
}

//初始化
var c Circle
c := new(Circle)
c := Circle{x:0, y:0, r:5}
c := Circle{0, 0, 5}
var tmp := c.x
func (c *Circle) area() float64 {
    return math.Pi * c.r * c.r
}

fmt.Println(c.area())

// 这里的area()就像一个类函数,是个接收器,

Interfaces

type Shape interface{
    area() float64
}

defer

用于资源的释放,在函数返回之前调用

f,err := os.Open(filename)
if err != nil {
    panic(err)
}
defer f.Close()

defer调用类似于栈,越往后越先调用

...

表示0个或者多个参数

func add(args ...int) int {
    
}

函数内创建函数

func main() {
    add := func(x, y int) int {
        return x+y
    }
    fmt.Println(add(1, 1))
}

map 用法

基本格式 map[keyType] valueType

var hello_map map[string]string  //声明,指向nil,没有内存空间
hello_map = make(map[string]string) // 初始化

hello_map := make(map[string]string)

hello_map := map[string]int {
    "ly": 22,
    "dy": 23,
}

遍历操作

for k, v := range hello_map {
    fmt.Println(hello_map[k])
}

三、常用包

3.1 testing

单元测试

  • go 的单元测试 包含在test 包内

  • 必须要import ( "testing" )

  • test文件必须以 *_test.go 格式命名,而且测试函数必须要以Test* 开头

func TestFoo(t *testing.T) { // .T代表单元测试 .B代表性能测试

t.Error("test fail")

}

  • 运行命令如下

go test -run ' ' # 运行所有的测试用例

go test -run Foo # 运行所有匹配“Foo” 的单元测试,比如函数名为“TestFooBar”

3.2 rpc

1, 导入 import "net/rpc"

2, 包功能的介绍:

用来调用一个对象通过网络提供的方法。服务注册一个可见的对象,注册后输出的方法就可以被远程调用了。

3,方法是这样

func (t *T) MethodName(argType T1, replyType *T2) error

其中T1和T2可以被序列化,T1由caller提供,T2表示需要返回给caller的参数

4,使用示例

  • server
package server

import "errors"

type Args struct {
	A, B int
}

type Quotient struct {
	Quo, Rem int
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
	*reply = args.A * args.B
	return nil
}

func (t *Arith) Divide(args *Args, quo *Quotient) error {
	if args.B == 0 {
		return errors.New("divide by zero")
	}
	quo.Quo = args.A / args.B
	quo.Rem = args.A % args.B
	return nil
}
// 服务呼叫阶段,call阶段
arith := new(Arith)
rpc.Register(arith) // server注册arith对象的服务,发布方法
rpc.HandleHTTP()  // 注册一个http handler,处理rpc 消息 发送给defaultserver
l, e := net.Listen("tcp", ":1234")  // server监听端口1234
if e != nil {
	log.Fatal("listen error:", e)
}
go http.Serve(l, nil)

完成以上工作,clients 就能看见Arith 服务,以及它的方法Arith.Multiply 和Arith.Divide

  • client
client, err := rpc.DialHTTP("tcp", serverAddress + ":1234") // 为了调用方法,client需要连接服务,dial
if err != nil {
	log.Fatal("dialing:", err)
}

//client同步通信
args := &server.Args{7,8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
	log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)

//client异步通信
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := <-divCall.Done	// will be equal to divCall
// check errors, print, etc.

四、并发

4.1 通过通信来共享数据

通过channels 来传递共享数据

Only one goroutine has access to the value at any given time. 一次只有一个协程访问数据

Do not communicate by sharing memory; instead, share memory by communicating.

unix下的管道(pipelines)解决同步问题

Although Go's approach to concurrency originates in Hoare's Communicating Sequential Processes (CSP), it can also be seen as a type-safe generalization of Unix pipes.

4.2 协程

  • 轻量级,花费仅仅比分配堆栈空间多一点点
  • 多路复用
  • 函数前面使用 go 关键字 在一个新的goroutine 中运行
go list.Sort()

func Announce(message string, delay time.Duration) {
    go func() {
        time.Sleep(delay)
        fmt.Println(message)
    }()  // Note the parentheses - must call the function.
}

4.3 channels 通道

reference: concurrency

ci := make(chan int)            // unbuffered channel of integers
cj := make(chan int, 0)         // unbuffered channel of integers
cs := make(chan *os.File, 100)  // buffered channel of pointers to Files

channel 使用make来初始化,maps也是

c := make(chan int)  // Allocate a channel.
// Start the sort in a goroutine; when it completes, signal on the channel.
go func() {
    list.Sort()
    c <- 1  // Send a signal; value does not matter.
}()
doSomethingForAWhile()
<-c   // Wait for sort to finish; discard sent value.

接收函数永远是被阻塞,只有当它接收到从channel来的数据

  • channel分为buffered 和 unbuffered
  • 如果unbuffered 发送方sender阻塞,直到接收方收到信号
  • 如果buffered 发送方只有在value复制到buffer时才阻塞,如果buffer满了,发送方等待,直到有receiver来获取数据
var sem = make(chan int, MaxOutstanding)
//实现一
func handle(r *Request) {
    sem <- 1    // Wait for active queue to drain.
    process(r)  // May take a long time.
    <-sem       // Done; enable next request to run.
}

func Serve(queue chan *Request) {
    for {
        req := <-queue
        go handle(req)  // Don't wait for handle to finish.
    }
}
//一会导致资源耗尽
// 实现二
func Serve(queue chan *Request) {
    for req := range queue {
        sem <- 1
        go func(req *Request) {
            process(req)
            <-sem
        }(req)
    }
}

同时只有maxOutstanding个call同时运行

posted @ 2019-11-22 18:18  Howardwang  阅读(219)  评论(0编辑  收藏  举报