golang 环境配置
- Linux系统
vim /etc/profile
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOROOT/bin:$GOBIN
go.mod
export GO111MODULE=on
export GOSUMDB=off
export GOPROXY=***
- Windows系统
go env -w GOPROXY=http://goproxy.***.com
go env -w GO111MOODULE=on
go env -w GOSUMDB=off
golang使用
- goland函数注释风格设置:File->Settings->Editor->Live Templates
- 代码同步
GMP模型
- Goroutine:相当于OS的进程控制块(Process Control Block);它包含:函数执行的指令和参数,任务对象,线程上下文切换,字段保护,和字段的寄存器。
- M:对应物理线程。
- P:golang的协程调度器。P的数量可以通过GOMAXPROCS设置。
调度器设计策略
1、复用线程:
- work stealing机制:当本线程无可运行的Goroutine时,尝试从其他线程绑定的P队列偷取G,而不是消毁线程。
-
hand off机制:当本线程因为Goroutine进行系统调用阻塞时,线程释放绑定的P,把P转移给其它空闲的线程执行。
2、抢占:在goroutine中要等待一个协程主动让CPU才执行下一个协程;在GO中,一个goroutine最多占用CPU 10ms, 防止其他goroutine被锁死。
3.利用并行:利用GOMAXPROCS设置P数量,最多有GPMAXPROCS个线程分布在多个CPU上同时执行。
4.全局G队列:当M执行work stealing从其它P的本地队列中偷不到G时,它可以从全局列队获取G.
runtime
golang 的 runtime 核心功能包括以下内容:协程(goroutine)调度、垃圾回收(GC)、内存分配
使得 golang 可以支持如 pprof、trace、race 的检测
- 1、内存泄漏:申请了内存,没有及时释放内存。
- 2、野指针:内存释放后还在使用,导致未定义的行为。
注:go不支持C++对指针偏移的操作。可以支持GC
一、GO的关键字:
包管理:package、import
变量:var、map、struct、interface、const、type
函数:func、return、defer
循环:if、else、switch、case、fallthought、default、for、break、continue、goto、range
并发:go、chan、select
a := []int{}
copy(a, []int{1, 2, 3})
fmt.Println(a) // >> [1 2 3]
fmt.Println(append(a, 1)) // >> [1 2 3 1]
b := []int{5}
copy(b, []int{1, 2, 3})
fmt.Println(b) // >> [1]
c := []int{5, 6, 7, 8}
copy(c, []int{1, 2, 3})
fmt.Println(c) // >> [1, 2, 3, 8]
二、GO的变量类型:
(1)整型
int(默认)、int8、int16、int32、int64、byte
uint、uint8、uint16、uint32、uint64
(2)浮点型:float32、float64(默认)
(3)复数:complex64、complex128(默认)
(4)数组:值拷贝、不同长度和不同类型的数组都是一个新类型
(5)切片:引用
(6)map:引用
(7)复合类型:interface、struct
三、GO的内置函数:append、cap、new、make、copy、len、delete、panic、recover
(1)append:向切片中添加一个或多个值
(2)cap:计算数组和切片已分配的内存空间
(3)new:传入一个结构体名,返回它的一个实例对象的一个引用
(4)make:为切片、map分配空间 ( make([]int, 3) make(map[int]int))
(5)copy:为切片进行值拷贝
(6)len:计算字符串、数组、切片、map当前已使用的空间个数
(7)delete:删除map中的一个key
(8)panic:恐慌、会从当前函数一直往调用该函数的那个函数扩散,直到遇到recover或者是扩散到main函数中
(9)recover:接收恐慌
协程
三个协和交替打印
package main
import (
"fmt"
"time"
)
func RunA(count int, ch1, ch2 chan int) {
for i := 0; i < 10; i++ {
<-ch1
fmt.Println(i)
ch2 <- i
}
}
func RunB(count int, ch2, ch3 chan int) {
for i := 0; i < 10; i++ {
<-ch2
fmt.Printf("%c\n", 'a'+byte(i))
ch3 <- i
}
}
func RunC(count int, ch1, ch3 chan int) {
for i := 0; i < 10; i++ {
<-ch3
fmt.Printf("%c\n", 'A'+byte(i))
ch1 <- i
}
}
func main() {
fmt.Println("Hello World")
count := 10
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
ch3 := make(chan int, 1)
// 启动多个goroutine
go RunA(count, ch1, ch2)
go RunB(count, ch2, ch3)
go RunC(count, ch1, ch3)
time.Sleep(time.Second * 10)
}
文件操作
package main
import (
"fmt"
"os"
)
func main() {
// 创建一个文件
file, err := os.Create("test.txt")
if err != nil {
fmt.Println("创建文件失败")
return
}
defer file.Close()
// 写入文件
_, err = file.WriteString("Hello World")
if err != nil {
fmt.Println("写入文件失败")
return
}
// 读取文件
file, err = os.Open("test.txt")
if err != nil {
fmt.Println("打开文件失败")
return
}
defer file.Close()
content, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("读取文件失败")
return
}
fmt.Println(string(content))
}
字符串操作
package main
import (
"fmt"
"strings"
)
func main() {
s := "Hello World"
fmt.Println(s[0:5]) // >> Hello
fmt.Println(s[:5]) // >> Hello
fmt.Println(s[5:]) // >> World
fmt.Println(s[5:10]) // >> World
fmt.Println(strings.ToUpper(s)) // >> HELLO WORLD
fmt.Println(strings.ToLower(s)) // >> hello world
fmt.Println(strings.Repeat(s, 3)) // >> Hello WorldHello WorldHello World
}
指针
package main
import "fmt"
func main() {
var a int = 10
var b *int = &a
fmt.Println(*b) // >> 10
c := 10
d := &c
fmt.Println(*d) // >> 10
}
标准库函数
字符串slice处理
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
s := []string{"Hello", "World"}
// 判断字符串是否包含子字符串
fmt.Println(strings.Contains(s[0], "Hello")) // >> true
fmt.Println(strings.Contains(s[0], "World")) // >> false
// 字符串的长度和大小
fmt.Println(len(s)) // >> 2
fmt.Println(cap(s)) // >> 2
fmt.Println(len(s[0])) // >> 5
// 字符串排序
sort.Slice(s, func(i, j int) bool {
return s[i] > s[j] // 降序
})
fmt.Println(s) // >> [World Hello]
}
类型转换
package main
import (
"fmt"
"strconv"
)
func main() {
// 字符串转整型
a := "100"
b, err := strconv.Atoi(a)
if err != nil {
fmt.Println("转换失败")
return
}
fmt.Println(b) // >> 100
// 字符串转浮点型
e, err := strconv.ParseFloat(a, 64)
if err != nil {
fmt.Println("转换失败")
return
}
fmt.Println(e) // >> 100
// 字符串转int64
f, err := strconv.ParseInt(a, 10, 64)
if err != nil {
fmt.Println("转换失败")
return
}
fmt.Println(f) // >> 100
// 整型转字符串
c := 100
d := strconv.Itoa(c)
fmt.Println(d) // >> 100
// 浮点型转字符串
g := 100.123
h := strconv.FormatFloat(g, 'f', 2, 64)
fmt.Println(h) // >> 100.12
// int64转字符串
i := int64(100)
j := strconv.FormatInt(i, 10)
fmt.Println(j) // >> 100
}
随机数
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 生成随机数种子,不然每次都会随机成0
rand.Seed(time.Now().UnixNano())
fmt.Println(rand.Intn(100)) // >> 66
// 生成0到(n-1)的随机整数 int32
fmt.Println(rand.Int31n(100)) // >> 66
// 生成0到(n-1)的随机整数 int64
fmt.Println(rand.Int63n(100)) // >> 66
}
并发
在 sync.WaitGroup(等待组)类型中,每个 sync.WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。
跟java的CountdownLatch差不多,也是阻塞等待所有任务完成之后再继续执行。
简单使用就是在创建一个任务的时候wg.Add(1),
任务完成的时候使用wg.Done()来将任务减一。
使用wg.Wait()来阻塞等待所有任务完成。
- (wg *WaitGroup) Add(delta int)
- (wg *WaitGroup) Done()
- (wg *WaitGroup) Wait()
package main
import (
"sync"
)
type httpPkg struct{}
func (httpPkg) Get(url string) {}
var http httpPkg
func main() {
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
// Increment the WaitGroup counter.
wg.Add(1)
// Launch a goroutine to fetch the URL.
go func(url string) {
// Decrement the counter when the goroutine completes.
defer wg.Done()
// Fetch the URL.
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()
}
接口请求读取
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 创建一个GET请求
req, err := http.NewRequest("GET", "https://www.baidu.com", nil)
if err != nil {
fmt.Println("创建请求失败")
return
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("发送请求失败")
return
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("读取响应体失败")
return
}
result := struct{
Code int `json:"code"`
Data string `json:"data"`
}{}
fmt.Println(string(body))
if err != json.Unmarshal(body, &result) {
fmt.Println("解析响应失败")
return
}
fmt.Println(result)
}
常用三方工具
• delve 本地代码调试工具
• goconvey是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多Web界面特性。
• goleak 本地排查内存泄露的工具
• go-wrk Go接口压测工具
• golint 代码风格检查
• revive 代码风格检查,比golint速度更快
• gocode 代码自动补全工具,可以在vim中使用