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 通道
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同时运行