├── goweb └── mvc.md ├── go源码分析 ├── 反射 │ ├── 类型判断.md │ ├── app.go │ ├── reflect.go │ └── 反射.md ├── 并发 │ ├── os.signer.md │ ├── 抢占式调度.md │ ├── waitgroup.go │ ├── map_rwmutex_r.go │ ├── 是否并发冲突测试.go │ ├── sync.RWMUtex.md │ ├── map_rwmutex.go │ ├── sync.watigroup.md │ ├── sync.Once.md │ ├── sync.Mutex.md │ ├── SafeMap.go │ └── README.md ├── 容器 │ ├── 双向链表.md │ ├── ring.md │ └── heap.md ├── 值与址 │ ├── README.md │ ├── array是值传递.go │ ├── slice是址传递.go │ ├── struct是值传递.go │ ├── pointslice.go │ ├── slice的copy方法.go │ ├── map是址传递.go │ ├── string值.go │ └── range关键字与slice-map需要注意的.go ├── 内存管理 │ ├── new_make.md │ ├── close.go │ ├── gc │ │ ├── README.md │ │ └── GC.md │ ├── testmap │ │ └── testmap.go │ ├── sizeof.go │ └── README.md ├── chan │ ├── channel_or_mutex.md │ ├── README.md │ ├── 死锁 │ │ └── close两次.go │ ├── 一个协程处理多个chan │ │ ├── README.md │ │ └── 一个协程处理多个chan.go │ ├── 同步 │ │ ├── not_happen_before.go │ │ ├── 同步.go │ │ └── happen_before.go │ ├── select用于阻塞监听goroutine.go │ ├── timeout │ │ └── 超时.go │ ├── goroutinueselect.go │ ├── 协程间通信 │ │ └── 协程间通信.go │ ├── selectchantest.go │ └── main.go ├── context │ ├── .README.md.swp │ └── README.md ├── 字节切片 │ ├── rune.md │ ├── array.test.go │ ├── bytes自动扩增.go │ ├── substring.go │ └── sliceselect.go ├── 位计算 │ ├── IntMax.go │ ├── jiou.go │ └── app.go ├── interface.md ├── os │ ├── README.md │ ├── hostname.go │ └── all.go ├── defer语句详细探讨 │ ├── defer_stack.go │ ├── defer.go │ └── defer_bibao.go ├── 容器类 │ ├── settest │ │ └── app.go │ ├── maptest │ │ └── MapTest.go │ ├── Set.go │ ├── list.go │ └── HashSet.go ├── string.md ├── slice │ └── slicetest.go ├── go │ └── types │ │ └── Packages.go ├── 运行时 │ ├── gotime.go │ ├── README.md │ └── select.go ├── 协程栈 │ ├── 系统调用.md │ └── README.md ├── slice.md ├── map.md ├── nil │ └── structnil.go ├── new_make.go ├── 编码解码 │ ├── base64.md │ └── json.go ├── buildin │ ├── 基础类型.md │ └── 内置函数.md ├── 加密 │ └── hmac.md └── net │ ├── goip.go │ └── README.md ├── 基本语言知识 ├── gotest.md ├── C的while等于go的for.md ├── README.md ├── bit.go ├── json.md ├── 流程控制 │ ├── for.md │ ├── deef.go │ ├── break.go │ └── defer.md ├── type │ └── typebyte.go ├── 匿名结构体.md ├── 闭包 │ ├── README.md │ └── closures.go ├── string_rune.md ├── 时间类型 │ ├── weekday.go │ ├── datetime.md │ └── comparison.go ├── file.md ├── 错误捕获 │ └── recover.go ├── 面向对象 │ └── 函数覆盖.go ├── 函数 │ └── func.go ├── 基本数据类型.md ├── gopackage.md ├── 枚举.go └── json_map_string.md ├── .gitignore ├── 环境及常用工具 ├── go_vscode.md ├── go_build.md ├── gotools.md ├── go_lint.md ├── go_package.md ├── liteide_go.md └── golang_linux_install.md ├── img ├── word.png ├── keyword.jpg └── gopackage.jpg ├── go第三方 ├── pg_note.md ├── mgo │ ├── mapstringinterface.go │ ├── main.go │ └── mongoapp.go └── SummerApp.go ├── golang代码规范.md ├── 数据结构与算法 └── 排序 │ └── slice_sort.go ├── golang-note.iml ├── XIAOMI ├── MIHOME.go └── ChildNet.go └── README.md /goweb/mvc.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go源码分析/反射/类型判断.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /基本语言知识/gotest.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | -------------------------------------------------------------------------------- /go源码分析/并发/os.signer.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /基本语言知识/C的while等于go的for.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /环境及常用工具/go_vscode.md: -------------------------------------------------------------------------------- 1 | https://github.com/Microsoft/vscode-go 2 | -------------------------------------------------------------------------------- /go源码分析/容器/双向链表.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/container/list/ 2 | 3 | -------------------------------------------------------------------------------- /go源码分析/容器/ring.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/container/ring/ 2 | 3 | circular lists -------------------------------------------------------------------------------- /img/word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaobyte/golang_note/HEAD/img/word.png -------------------------------------------------------------------------------- /基本语言知识/README.md: -------------------------------------------------------------------------------- 1 | # go基础 2 | 3 | ![](/img/keyword.jpg) 4 | 5 | ![](/img/word.jpg) -------------------------------------------------------------------------------- /img/keyword.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaobyte/golang_note/HEAD/img/keyword.jpg -------------------------------------------------------------------------------- /go第三方/pg_note.md: -------------------------------------------------------------------------------- 1 | ## 基本类型 2 | 3 | integers 4 | floats 5 | string 6 | bool 7 | time.Time 8 | -------------------------------------------------------------------------------- /img/gopackage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaobyte/golang_note/HEAD/img/gopackage.jpg -------------------------------------------------------------------------------- /go源码分析/值与址/README.md: -------------------------------------------------------------------------------- 1 | 值传递: 2 | array,struct 3 | 4 | 址传递: 5 | slice,map 6 | 7 | 传递值,但长度可变 8 | string -------------------------------------------------------------------------------- /go源码分析/内存管理/new_make.md: -------------------------------------------------------------------------------- 1 | # new make 2 | 3 | new(struct)初始化零值,返回一个指针 4 | 5 | make(),map或者slice,或者chan -------------------------------------------------------------------------------- /基本语言知识/bit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println(1<<48) 7 | } 8 | -------------------------------------------------------------------------------- /go第三方/mgo/mapstringinterface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | 6 | "log" 7 | ) 8 | -------------------------------------------------------------------------------- /go源码分析/chan/channel_or_mutex.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | + 出让 cpu 并且让另一个 goroutine 获得执行机会,这个切换周期不低,远高于 Mutex 检查竞争状态的成本(后者通常只是一个原子操作) -------------------------------------------------------------------------------- /go源码分析/context/.README.md.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaobyte/golang_note/HEAD/go源码分析/context/.README.md.swp -------------------------------------------------------------------------------- /go源码分析/chan/README.md: -------------------------------------------------------------------------------- 1 | ## goroutine 2 | 3 | + 无上限 (只受限于内存) 4 | + 创建/切换成本低 5 | 6 | 7 | ## channel 8 | + 本质上是一个 MessageQueue -------------------------------------------------------------------------------- /go源码分析/字节切片/rune.md: -------------------------------------------------------------------------------- 1 | # rune 2 | 3 | https://golang.org/pkg/bytes/#Runes 4 | 5 | https://golang.org/pkg/bytes/#ContainsRune -------------------------------------------------------------------------------- /go源码分析/context/README.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/context/ 2 | 3 | 携带的最后期限,取消信号,并在API边界和流程之间的其他请求范围的值 4 | 5 | 上下文的函数是由多个够程同时使用安全 -------------------------------------------------------------------------------- /基本语言知识/json.md: -------------------------------------------------------------------------------- 1 | ## json大小写问题 2 | 3 | ``` 4 | type js struct{ 5 | Name string `json:"name"` 6 | } 7 | f 8 | ``` 9 | -------------------------------------------------------------------------------- /go源码分析/位计算/IntMax.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println(int64(-1 << 63)) 7 | fmt.Println(int64(1<<63 - 1)) 8 | } 9 | -------------------------------------------------------------------------------- /环境及常用工具/go_build.md: -------------------------------------------------------------------------------- 1 | https://golang.org/pkg/go/build/ 2 | 3 | ``` 4 | $ cd sourcefolder 5 | $ CGO_ENABLED=0 6 | GOOS=linux GOARCH=amd64 gobuild 7 | ``` 8 | -------------------------------------------------------------------------------- /环境及常用工具/gotools.md: -------------------------------------------------------------------------------- 1 | ## 文档查看 2 | ``` 3 | godoc -http=:8090 4 | ``` 5 | 然后打开 6 | 7 | [go](http://localhost:8090/pkg/) 8 | 9 | cd $GOPATH/bin 10 | ./gotour 11 | -------------------------------------------------------------------------------- /go源码分析/interface.md: -------------------------------------------------------------------------------- 1 | # interface 2 | 3 | interface实际上是一个结构体,包括两个成员,一个是指向数据的指针,一个包含了成员的类型信息 4 | ``` 5 | struct Iface 6 | { 7 | Itab* tab; 8 | void* data; 9 | }; 10 | ``` -------------------------------------------------------------------------------- /基本语言知识/流程控制/for.md: -------------------------------------------------------------------------------- 1 | for 2 | ``` 3 | for index,char := range string {} 4 | for index,value := range array {} 5 | for index,value := range slice {} 6 | for key,value := range map {} 7 | ``` -------------------------------------------------------------------------------- /go源码分析/字节切片/array.test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type S struct { 6 | } 7 | 8 | func main() { 9 | len := 9 10 | a := [len]S{} 11 | fmt.Println(a) 12 | } 13 | -------------------------------------------------------------------------------- /go源码分析/chan/死锁/close两次.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | c := make(chan int) 7 | close(c) 8 | 9 | i, isClose := <-c 10 | fmt.Println(i, isClose) 11 | } 12 | -------------------------------------------------------------------------------- /go源码分析/os/README.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/os/ 2 | ## 运行 3 | + func Exit(code int) 4 | 5 | 6 | ## 权限修改 7 | 8 | ## 环境变量 9 | 10 | ## 文件夹操作 11 | 12 | ## 文件操作 13 | 14 | ## 进程操作 15 | 16 | ## 信号量 -------------------------------------------------------------------------------- /go源码分析/位计算/jiou.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | for i := 0; i < 100; i++ { 5 | if i%2 == 0 { 6 | println(i) 7 | } 8 | if i&0x1 == 0 { 9 | println(i) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /go源码分析/并发/抢占式调度.md: -------------------------------------------------------------------------------- 1 | # work-stealing的调度算法: 2 | 3 | 每个P维护一个G队列; 4 | 当一个G被创建出来,或者变为可执行状态时,就把他放到P的可执行队列中; 5 | 当一个G执行结束时,P会从队列中把该G取出;如果此时P的队列为空,即没有其他G可以执行, 就随机选择另外一个P,从其可执行的G队列中偷取一半。 6 | 该算法避免了在Goroutine调度时使用全局锁。 7 | -------------------------------------------------------------------------------- /go源码分析/defer语句详细探讨/defer_stack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 0; i < 10; i++ { 7 | defer func(v int) { 8 | fmt.Println("num=", v) 9 | }(i) 10 | } 11 | } 12 | 13 | // 14 | -------------------------------------------------------------------------------- /go源码分析/容器类/settest/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gowebdeveloper/golang-note/基本语言知识/容器类" 4 | 5 | func main() { 6 | s:= 容器类.NewHashSet() 7 | s.Add("123") 8 | s.Add("123") 9 | s.Add("123") 10 | } 11 | -------------------------------------------------------------------------------- /golang代码规范.md: -------------------------------------------------------------------------------- 1 | # golang代码规范 2 | 3 | ## 一.通过golint检查 4 | + 变量 5 | + 函数名 6 | + 包名 7 | + 结构体名 8 | 9 | ## 二.通过golint 检查注释 10 | 11 | + 所有大写的公共函数、公共变量的注释 12 | 13 | ## 三.test自测 14 | + 复杂逻辑的函数,应该写xxx_test.go文件和自测函数 15 | 16 | 17 | -------------------------------------------------------------------------------- /go源码分析/string.md: -------------------------------------------------------------------------------- 1 | #string 2 | 3 | string类型的底层是一个C struct. 4 | 5 | 成员str为字符数组,len为字符数组长度。golang的字符串是不可变类型,对string类型的变量初始化意味着会对底层结构的初始化 6 | 7 | ``` 8 | struct String 9 | { 10 | byte* str; 11 | intgo len; 12 | }; 13 | ``` -------------------------------------------------------------------------------- /go源码分析/值与址/array是值传递.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var array [5]float64=[5]float64{1,2,3,4,5} 7 | 8 | news:=array 9 | 10 | array[4]=5.1 11 | news[1]=1.1 12 | fmt.Println(array,news) 13 | } 14 | -------------------------------------------------------------------------------- /go源码分析/值与址/slice是址传递.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var slice []float64 = []float64{1, 2, 3, 4, 5} 7 | 8 | news := slice 9 | 10 | slice[4] = 5.1 11 | news[1] = 1.1 12 | fmt.Println(slice, news) 13 | } 14 | -------------------------------------------------------------------------------- /go源码分析/os/hostname.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | host, err := os.Hostname() 10 | if err != nil { 11 | fmt.Printf("%s", err) 12 | } else { 13 | fmt.Printf("%s", host) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /go源码分析/slice/slicetest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "unsafe" 7 | ) 8 | 9 | func main() { 10 | s := []int{1, 2, 3, 4, 5, 6, 7} 11 | p1 := unsafe.Pointer(&s[:0]) 12 | //p3 := uintptr(s[:0]) 13 | fmt.Printf(p1) 14 | } 15 | -------------------------------------------------------------------------------- /数据结构与算法/排序/slice_sort.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sort" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | slice_m:=[]int{3,2,4,5,3,5,25,3,2,1,4,2,4,6,63,2,3,3} 10 | fmt.Println(slice_m) 11 | sort.Ints(slice_m) 12 | fmt.Println(slice_m) 13 | } -------------------------------------------------------------------------------- /go源码分析/go/types/Packages.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/types" 6 | ) 7 | 8 | func main() { 9 | p := types.NewPackage("github.com/golangframework", "map256") 10 | 11 | p.MarkComplete() 12 | fmt.Println(p, p.Complete()) 13 | } 14 | -------------------------------------------------------------------------------- /go源码分析/容器类/maptest/MapTest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | s:=make(map[string]int) 7 | s["1"]=0 8 | s["2"]=1 9 | 10 | value,have:=s["1"] 11 | fmt.Println(have,value) 12 | v,h:=s["3"] 13 | fmt.Println(h,v) 14 | } 15 | -------------------------------------------------------------------------------- /go源码分析/运行时/gotime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | for { 10 | select { 11 | case <-time.Tick(time.Second): 12 | { 13 | fmt.Println(time.Now().String()[:19]) 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /基本语言知识/type/typebyte.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type N struct { 6 | A int `json:"a"` 7 | }byte 8 | 9 | func (this *N) Decode() byte { 10 | return byte(*this) 11 | } 12 | func main() { 13 | n := N(1) 14 | fmt.Println(n.Decode()) 15 | } 16 | -------------------------------------------------------------------------------- /go源码分析/字节切片/bytes自动扩增.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | var bs []byte = make([]byte, 1024) 10 | ioutil.WriteFile("bs.iso", bs, os.ModePerm) 11 | 12 | var toread []byte = make([]byte, 0) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /环境及常用工具/go_lint.md: -------------------------------------------------------------------------------- 1 | 1. 点击Edit Configuration, 添加一个 `Go Application`,设置Before launch: External tool 2 | 2. 点击+,选择`Run External tool`,再点击+,create tool 3 | 3. 设置好Name: golint 选择运行的Progam: $GOPATH/bin/golint,设置Parameters: ., 设置Working directory: $FileDir$, 勾选上显示信息在console 4 | 5 | -------------------------------------------------------------------------------- /go源码分析/容器类/Set.go: -------------------------------------------------------------------------------- 1 | package 容器类 2 | 3 | 4 | 5 | type Set interface { 6 | Add(e interface{}) bool 7 | Remove(e interface{}) 8 | Clear() 9 | Contains(e interface{}) bool 10 | Len() int 11 | Equal(other Set) bool 12 | Elements() []interface{} 13 | String() string 14 | } -------------------------------------------------------------------------------- /go源码分析/位计算/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | fmt.Println(0 << 0) 8 | fmt.Println(0 << 1) 9 | fmt.Println(1 << 0) 10 | fmt.Println(1 << 1) 11 | fmt.Println(1 << 2) 12 | fmt.Println(1 << 3) 13 | 14 | fmt.Println(3 << 3) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /go源码分析/协程栈/系统调用.md: -------------------------------------------------------------------------------- 1 | Golang自己接管系统调用,调度器便可以在进出系统调用时做一些你所不明白的优化,这里我要带你弄清楚调度器怎么做优化的。 2 | 进入系统调用前 3 | 4 | 我们前面说过,系统调用是一个相对耗时的过程。一旦P中的某个G进入系统调用状态而阻塞了该P内的其他协程。此时调度器必须得做点什么吧,这就是调度器在进入系统调用前call runtime·entersyscall目的所在。 5 | 6 | 7 | 从系统调用返回后 8 | 9 | 从系统调用返回后,也要告诉调度器,因为需要调度器做一些事情,根据前面系统调用的实现,具体实现是: -------------------------------------------------------------------------------- /go源码分析/slice.md: -------------------------------------------------------------------------------- 1 | # slice 2 | 3 | slice类型的底层同样是一个C struct 4 | ``` 5 | struct Slice 6 | { // must not move anything 7 | byte* array; // actual data 8 | uintgo len; // number of elements 9 | uintgo cap; // allocated number of elements 10 | }; 11 | ``` 12 | 13 | slice1和slice2可以共用一个底层数组 -------------------------------------------------------------------------------- /基本语言知识/匿名结构体.md: -------------------------------------------------------------------------------- 1 | # 匿名结构体 2 | 3 | ``` 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | ) 9 | 10 | func main() { 11 | var user struct{Name string; Gender int} 12 | user.Name = "dotcoo" 13 | user.Gender = 1 14 | fmt.Printf("%#v\n", user) 15 | } 16 | ``` 17 | 18 | -------------------------------------------------------------------------------- /基本语言知识/闭包/README.md: -------------------------------------------------------------------------------- 1 | 闭包实例,这些实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。 2 | 3 | 闭包函数是把创建时,引用到的外部数据复制了一份,与函数一起组成了一个整体。 4 | 5 | 闭包函数出现的条件: 6 | 1.被嵌套的函数引用到非本函数的外部数据,而且这外部数据不是“全局变量” 7 | 2.函数被独立了出来(被父函数返回或赋值给其它函数或变量了) 8 | 9 | 回来看闭包的定义:闭包是什么,闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)。 -------------------------------------------------------------------------------- /go源码分析/map.md: -------------------------------------------------------------------------------- 1 | # map 2 | 3 | {$go}/src/runtime/hashmap.go 4 | 5 | golang的map实现并不是像c++一样使用红黑树,而是使用了hashmap,用数组来实现 6 | 7 | golang的map使用了桶的概念,元素是被hash到桶存储,每个桶预设是存储八个kv,而且在头部有一个uint8 tophash[8]的结构,存储每个key的高八位(即hash(key) » (64 - 8)),如果该位置未被放置元素,则有一个特殊的标志Empty 8 | 9 | 利用了overflow指针,可以无限的增长,类似链表 10 | 11 | -------------------------------------------------------------------------------- /go源码分析/字节切片/substring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a:="中12国123abc的的的" 7 | pre:="中12国" 8 | 9 | fmt.Println(substring(a,pre)) 10 | } 11 | 12 | func substring(str,prefix string)( string){ 13 | result:=[]rune(str)[len([]rune(prefix)):] 14 | return string(result) 15 | } -------------------------------------------------------------------------------- /go源码分析/nil/structnil.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type A struct { 6 | Name string 7 | } 8 | type B struct { 9 | A A 10 | Name string 11 | } 12 | type C struct { 13 | A *A 14 | Name string 15 | } 16 | 17 | func main() { 18 | fmt.Println(new(C)) 19 | fmt.Println(new(B)) 20 | } 21 | -------------------------------------------------------------------------------- /go源码分析/值与址/struct是值传递.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | n:=N{255,255,255} 7 | m:=n 8 | n.R=0 9 | m.B=0 10 | fmt.Println(n,m) 11 | 12 | p:=&N{255,255,255} 13 | q:=p 14 | p.R=0 15 | q.B=0 16 | fmt.Println(p,q) 17 | } 18 | 19 | type N struct { 20 | R,G,B int 21 | } 22 | -------------------------------------------------------------------------------- /go源码分析/new_make.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | d := make(map[int]int, 2000*10000) 10 | t1 := time.Now().Unix() 11 | for i := 0; i < 2000*10000; i++ { 12 | d[i] = i 13 | } 14 | fmt.Println(len(d)) 15 | fmt.Println(time.Now().Unix() - t1) 16 | } 17 | -------------------------------------------------------------------------------- /go源码分析/值与址/pointslice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type A struct { 6 | B int 7 | } 8 | 9 | func main() { 10 | l := make([]*A, 0) 11 | in := make([]int, 0) 12 | for _, a := range l { 13 | if a != nil { 14 | in = append(in, a.B) 15 | fmt.Println(a, a.B, in) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /go源码分析/值与址/slice的copy方法.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | /** 5 | 该函数主要是切片(slice)的拷贝,不支持数组 6 | 将第二个slice里的元素拷贝到第一个slice里,拷贝的长度为两个slice中长度较小的长度值 7 | 示例: 8 | */ 9 | func main() { 10 | s := []int{1,2,3}; 11 | fmt.Println(s) ;//[1 2 3] 12 | copy(s,[]int{4,5,6,7,8,9}); 13 | fmt.Println(s); //[4 5 6] 14 | } 15 | -------------------------------------------------------------------------------- /go源码分析/内存管理/close.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | /* 6 | push 7 | */ 8 | func main() { 9 | in := make(chan int, 1) 10 | 11 | in <- 1 12 | 13 | i := <-in 14 | fmt.Println(i) 15 | close(in) 16 | 17 | if v, ok := <-in; ok { 18 | fmt.Println(v) 19 | } else { 20 | fmt.Println(ok) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /基本语言知识/流程控制/deef.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | v := f1() 7 | fmt.Println(v) 8 | } 9 | 10 | func f1() (i int) { 11 | 12 | defer func() { 13 | i++ 14 | }() 15 | return 0 16 | } 17 | 18 | func f2() (i int) { 19 | 20 | defer func(i int) { 21 | i++ 22 | }(i) 23 | return 0 24 | } 25 | -------------------------------------------------------------------------------- /环境及常用工具/go_package.md: -------------------------------------------------------------------------------- 1 | # go package详解 2 | 3 | GO语言中package用于封装一个相对独立的功能提供给外部使用 4 | 5 | 1. package会对应一个目录 这点与Java类似 6 | 7 | 2. package中的源代码存放目录是package最后一个/结束的准,如package math/rand,那么所源代码都在rand目录下 8 | 9 | 3. main是一个特殊的package名字,类似Java的main函数,GO的可执行程序必须在main package下 10 | 11 | 4. 以大写字母开头的函数才会被导出(外部访问)。这点类似Java和访问权限控制,只是太隐晦了 12 | -------------------------------------------------------------------------------- /go源码分析/chan/一个协程处理多个chan/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | fatal error: all goroutines are asleep - deadlock! 3 | ``` 4 | 出错信息的意思是: 5 | 在main goroutine线,期望从管道中获得一个数据,而这个数据必须是其他goroutine线放入管道的 6 | 但是其他goroutine线都已经执行完了(all goroutines are asleep),那么就永远不会有数据放入管道。 7 | 所以,main goroutine线在等一个永远不会来的数据,那整个程序就永远等下去了。 8 | 这显然是没有结果的,所以这个程序就说“算了吧,不坚持了,我自己自杀掉,报一个错给代码作者,我被deadlock了” -------------------------------------------------------------------------------- /基本语言知识/string_rune.md: -------------------------------------------------------------------------------- 1 | # string类型与rune 2 | 3 | ##len() 4 | ```go 5 | s:="go语言编程" 6 | var l int 7 | l=len([]rune(s)) 8 | ``` 9 | 10 | ##substring() 11 | ```go 12 | s:="go语言编程" 13 | rs:=[]rune(s) 14 | var str=rs[2:6] 15 | fmt.Println(string(str)) 16 | 17 | ``` 18 | 19 | ##string to byte 20 | ```byte 21 | s1:="abcd" 22 | b1:=[]byte(s1) 23 | ``` 24 | -------------------------------------------------------------------------------- /基本语言知识/时间类型/weekday.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | //时间戳 10 | t := time.Now() 11 | 12 | fmt.Println(t.Weekday().String()) 13 | fmt.Println(int(t.Weekday())) 14 | fmt.Println(int(t.Month())) 15 | fmt.Println(int(t.Day())) 16 | y, m, d := t.Date() 17 | fmt.Println(y, m, d) 18 | } 19 | -------------------------------------------------------------------------------- /基本语言知识/流程控制/break.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 0; i < 100; i++ { 7 | for j := 0; j < 100; j++ { 8 | switch i * j % 10 { 9 | case 1: 10 | fmt.Println(i, j) 11 | break 12 | 13 | } 14 | fmt.Println("break 0") 15 | } 16 | fmt.Println("break 1") 17 | } 18 | fmt.Println("break 2") 19 | } 20 | -------------------------------------------------------------------------------- /基本语言知识/file.md: -------------------------------------------------------------------------------- 1 | #file相关处理包及字符串与二进制函数 2 | 3 | ##ioutil 4 | ioutil非常简单,一次把文件的所有内容都读出来。如果文件较大,会占用很多内存,需要小心。 5 | ``` go 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "io/ioutil" 11 | ) 12 | 13 | func main() { 14 | buff, err := ioutil.ReadFile("d:\\test.txt") 15 | if err != nil { 16 | panic("open file failed!") 17 | } 18 | fmt.Print(string(buff)) 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /基本语言知识/时间类型/datetime.md: -------------------------------------------------------------------------------- 1 | # go 时间类型 2 | time类型的String()方法,会生成 3 | 4 | ```go 5 | 2006-01-02 15:04:05.999999999 -0700 MST 6 | ``` 7 | 从字符串截取前19个字符,刚好就是我们需要的 8 | ```go 9 | import ( 10 | "time" 11 | ) 12 | 13 | time.Now().String()[:19] 14 | 2006-01-02 15:04:05 15 | ``` 16 | 字符串,转时间 17 | ``` 18 | t, err := time.Parse("2006-01-02 15:04:05", time.Now().String()[:19]) 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /go源码分析/chan/同步/not_happen_before.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var c = make(chan int, 1) 8 | var a string 9 | 10 | func f() { 11 | a = "hello, world" // (1) 12 | <-c // (2) 13 | } 14 | func main() { 15 | go f() 16 | c <- 0 // (3) 17 | fmt.Println(a) // (4) 18 | } 19 | 20 | /* 21 | 这段代码不再有任何同步保证,使得(2) happens-before (3) 22 | */ 23 | -------------------------------------------------------------------------------- /go源码分析/chan/select用于阻塞监听goroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | func main() { 6 | 7 | print(1) 8 | a := make(chan int, 1) 9 | b := make(chan int, 1) 10 | b <- 1 11 | a <- 0 12 | for { 13 | select { 14 | case A := <-a: 15 | print(A) 16 | a <- 0 17 | case B := <-b: 18 | print(B) 19 | b <- 1 20 | } 21 | time.Sleep(time.Second) 22 | } 23 | 24 | print(2) 25 | } 26 | -------------------------------------------------------------------------------- /go源码分析/defer语句详细探讨/defer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func defer_call() { 6 | defer func() { 7 | fmt.Println("before recover") 8 | }() 9 | 10 | defer func() { 11 | e := recover() 12 | fmt.Println("recover ", e) 13 | }() 14 | 15 | defer func() { 16 | fmt.Println("after recover") 17 | }() 18 | 19 | panic("panic info") 20 | } 21 | func main() { 22 | defer_call() 23 | } 24 | -------------------------------------------------------------------------------- /go源码分析/defer语句详细探讨/defer_bibao.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func calc(index string, a, b int) int { 6 | ret := a + b 7 | fmt.Println(index, a, b, ret) 8 | return ret 9 | } 10 | func main() { 11 | a := 1 12 | b := 2 13 | 14 | defer calc("1", a, calc("10", a, b)) // "1",1,3("10",1,2,3),4 15 | a = 0 16 | defer calc("2", a, calc("20", a, b)) //"2",0,2("20",0,2,2),2 17 | b = 1 18 | } 19 | -------------------------------------------------------------------------------- /环境及常用工具/liteide_go.md: -------------------------------------------------------------------------------- 1 | #liteide安装指南 2 | 3 | ##go最新版本源码下载地址 4 | 5 | https://go.googlesource.com/go/+ 6 | 7 | 安装包下载地址 8 | 9 | https://golang.org/dl/ 10 | 11 | 解压 12 | 13 | ##liteide最新版本地址 14 | 15 | https://github.com/visualfc/liteide/releases 16 | 17 | 安装 18 | 19 | ##设置goroot gopath 20 | 21 | ``` 22 | # native compiler drawin amd64 23 | 24 | GOROOT=/usr/local/go 25 | GOPATH=/MacData/GOPATH 26 | ``` 27 | -------------------------------------------------------------------------------- /go源码分析/内存管理/gc/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## GOGC 3 | 4 | GOGC 是Go Runtime最早支持的环境变量,甚至比GOROOT还早,几乎无人不知。GOGC 用于控制GC的处发频率, 其值默认为100, 5 | 6 | 意为直到自上次垃圾回收后heap size已经增长了100%时GC才触发运行。即是GOGC=100意味着live heap size 每增长一倍,GC触发运行一次。 7 | 8 | 如设定GOGC=200, 则live heap size 自上次垃圾回收后,增长2倍时,GC触发运行, 总之,其值越大则GC触发运行频率越低, 反之则越高, 9 | 10 | 如果GOGC=off 则关闭GC. 11 | 12 | 虽然go 1.5引入了低延迟的GC, 但是GOGC对GC运行频率的影响不变, 仍然是其值大于100,则越大GC运行频率越高, 13 | 14 | 反之则越低。 -------------------------------------------------------------------------------- /go源码分析/字节切片/sliceselect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func remoteslice(s *([]byte)) { 6 | s = &([]byte{0x1, 0x2}) 7 | } 8 | func remotemap(m map[string]string) { 9 | m["s"] = "sdf" 10 | } 11 | func main() { 12 | s := []byte{0x1, 0x2, 3, 4, 5, 6, 7, 8, 9, 0} 13 | remoteslice(&s) 14 | fmt.Println(s) 15 | 16 | m := make(map[string]string) 17 | remotemap(m) 18 | 19 | fmt.Println(m) 20 | } 21 | -------------------------------------------------------------------------------- /go源码分析/chan/timeout/超时.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | //不永久等别人的结果,对方可能有异常 (考虑timeout) 8 | 9 | func main() { 10 | done := make(chan int, 1) 11 | go func() { 12 | time.Sleep(4 * time.Second) 13 | done <-0 14 | }() 15 | 16 | select { 17 | case result := <-done: 18 | fmt.Println(result) 19 | case <- time.After(3 * time.Second): 20 | fmt.Println("timeout") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go源码分析/os/all.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(os.Getpid(), "Getpid") 10 | fmt.Println("Getegid", os.Getegid()) 11 | fmt.Println("Geteuid", os.Geteuid()) 12 | fmt.Println(os.Getgroups()) 13 | 14 | fmt.Print("Getwd") 15 | fmt.Println(os.Getwd()) 16 | fmt.Println("Executable", os.Executable()) 17 | fmt.Println("Hostname", os.Hostname()) 18 | } 19 | -------------------------------------------------------------------------------- /基本语言知识/错误捕获/recover.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main(){ 6 | defer func(){ // 必须要先声明defer,否则不能捕获到panic异常 7 | fmt.Println("c") 8 | if err:=recover();err!=nil{ 9 | fmt.Println(err) // 这里的err其实就是panic传入的内容,55 10 | } 11 | fmt.Println("d") 12 | }() 13 | f_recover() 14 | } 15 | 16 | func f_recover(){ 17 | fmt.Println("a") 18 | panic(55) 19 | fmt.Println("b") 20 | fmt.Println("f") 21 | } -------------------------------------------------------------------------------- /go源码分析/容器类/list.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | // 生成队列 10 | l := list.New() 11 | // 入队, 压栈 12 | l.PushBack(1) 13 | l.PushBack(2) 14 | l.PushBack(3) 15 | l.PushBack(4) 16 | // 出队 17 | i1 := l.Front() 18 | l.Remove(i1) 19 | fmt.Printf("%d\n", i1.Value) 20 | // 出栈 21 | i4 := l.Back() 22 | l.Remove(i4) 23 | fmt.Printf("%d\n", i4.Value) 24 | } 25 | -------------------------------------------------------------------------------- /基本语言知识/面向对象/函数覆盖.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Parent struct { 6 | } 7 | 8 | func (p *Parent) MethodB() { 9 | fmt.Println("MethodB from parent") 10 | } 11 | 12 | func (p *Parent) MethodA() { 13 | fmt.Println("MethodA from parent") 14 | p.MethodB() 15 | } 16 | 17 | type Child struct { 18 | Parent 19 | } 20 | 21 | func main() { 22 | c := Child{} 23 | c.MethodA() 24 | } 25 | 26 | //这道题目, 27 | -------------------------------------------------------------------------------- /基本语言知识/函数/func.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Atype struct { 6 | name string 7 | } 8 | 9 | func do(this *Atype) (result *Atype) { 10 | this.name = "lipeng" 11 | return this 12 | } 13 | 14 | func doing() (result Atype) { 15 | return 16 | } 17 | func domap() (result map[string]interface{}) { 18 | return 19 | } 20 | func main() { 21 | var a Atype 22 | fmt.Println(do(&a)) 23 | fmt.Println(domap()) 24 | } 25 | -------------------------------------------------------------------------------- /go源码分析/chan/同步/同步.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("1") 7 | c := make(chan int) // Allocate a channel. 8 | // Start the sort in a goroutine; when it completes, signal on the channel. 9 | go func() { 10 | fmt.Println("2") 11 | c <- 1 // Send a signal; value does not matter. 12 | fmt.Println("3") 13 | }() 14 | fmt.Println("4") 15 | <-c // 主协程 等待 16 | fmt.Println("5") 17 | } 18 | -------------------------------------------------------------------------------- /基本语言知识/闭包/closures.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type colsure func(*int) 9 | 10 | var add colsure = func(v *int) { 11 | for { 12 | (*v)++ 13 | } 14 | 15 | } 16 | var miux colsure = func(v *int) { 17 | for { 18 | (*v)-- 19 | } 20 | } 21 | 22 | func main() { 23 | i := 0 24 | go add(&i) 25 | go miux(&i) 26 | 27 | for { 28 | time.Sleep(time.Second) 29 | fmt.Println(i) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /go源码分析/值与址/map是址传递.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int=map[string]int{ 7 | "1":10, 8 | "2":20, 9 | "3":30, 10 | } 11 | 12 | var n map[string]int=map[string]int{ 13 | "1":10, 14 | "2":20, 15 | "3":30, 16 | } 17 | n=m 18 | changemap(m) 19 | changemap(n) 20 | fmt.Println(m,n) 21 | fmt.Println(m,n) 22 | } 23 | func changemap(m map[string]int) { 24 | m["1"]=40; 25 | m["3"]=60; 26 | } -------------------------------------------------------------------------------- /go源码分析/值与址/string值.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var s="我是字符串" 7 | fmt.Println(&s) 8 | var s2=s 9 | fmt.Println(&s2) 10 | 11 | 12 | var s3 ="我" 13 | s_string(s3) 14 | fmt.Println(&s3,len(s3)) 15 | s3+="1" 16 | s_string(s3) 17 | fmt.Println(&s3,len(s3)) 18 | s3+="2" 19 | s_string(s3) 20 | fmt.Println(&s3,len(s3)) 21 | } 22 | func s_string(s string) { 23 | fmt.Println("func",&s,"发生了值copy") 24 | 25 | } 26 | -------------------------------------------------------------------------------- /golang-note.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /go源码分析/运行时/README.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/runtime/ 2 | 3 | ## 常用函数 4 | 5 | + func GOROOT() string 6 | 7 | + func NumCPU() int 8 | NumCPU returns the number of logical CPUs usable by the current process. 9 | 10 | + func NumGoroutine() int 11 | NumGoroutine returns the number of goroutines that currently exist. 12 | 13 | + func Version() string 14 | , a release tag like "go1.3" 15 | 16 | + func (f *Func) Name() string 17 | Name returns the name of the function. -------------------------------------------------------------------------------- /go源码分析/并发/waitgroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | var wg sync.WaitGroup 10 | wg.Add(20) 11 | for i := 0; i < 10; i++ { 12 | 13 | go func() { 14 | wg.Done() 15 | //defer wg.Add(-1) 16 | fmt.Println("i", i) 17 | }() 18 | } 19 | for i := 0; i < 10; i++ { 20 | go func(n int) { 21 | wg.Done() 22 | //defer wg.Add(-1) 23 | fmt.Println("j", n) 24 | }(i) 25 | } 26 | wg.Wait() 27 | } 28 | -------------------------------------------------------------------------------- /go源码分析/运行时/select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | runtime.GOMAXPROCS(1) 10 | for { 11 | int_chan := make(chan int, 1) 12 | string_chan := make(chan string, 1) 13 | int_chan <- 1 14 | string_chan <- "呵呵" 15 | 16 | select { 17 | case v := <-int_chan: 18 | fmt.Println(v, "out put") 19 | case v := <-string_chan: 20 | panic(v + "out put") 21 | } 22 | } 23 | } 24 | 25 | // 此题目,说明select函数内部的case,是随机的 26 | -------------------------------------------------------------------------------- /环境及常用工具/golang_linux_install.md: -------------------------------------------------------------------------------- 1 | ``` shell 2 | ~$ sudo apt-get install git 3 | ~$ sudo apt-get install gcc 4 | 下载最新版 5 | ~$ wget http://www.golangtc.com/static/go/go1.6beta1/go1.6beta1.linux-amd64.tar.gz 6 | 用tar 命令来解压压缩包 7 | tar -zxvf 8 | 接着我们要添加环境变量 9 | sudo gedit /etc/profile 10 | 11 | export GOROOT=/usr/local/go 12 | export GOBIN=$GOROOT/bin 13 | export PATH=$PATH:$GOBIN 14 | export GOPATH=/media/timeloveboy/WinData/GOPATH 15 | 16 | 17 | 更新一下环境变量 18 | source /ect/profile 19 | ``` -------------------------------------------------------------------------------- /go源码分析/chan/goroutinueselect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func gorouting(ch chan int) { 9 | 10 | i := 0 11 | 12 | i++ 13 | for { 14 | ch <- i 15 | fmt.Println(i) 16 | <-ch 17 | i++ 18 | time.Sleep(time.Second) 19 | } 20 | } 21 | func main() { 22 | ch := make(chan int, 1) 23 | go gorouting(ch) 24 | for { 25 | ch <- 0 26 | fmt.Println("I want runing") 27 | <-ch 28 | time.Sleep(time.Second * 5) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /go源码分析/编码解码/base64.md: -------------------------------------------------------------------------------- 1 | ``` 2 | func Decode(raw []byte) []byte { 3 | var buf bytes.Buffer 4 | decoded := make([]byte, 215) 5 | buf.Write(raw) 6 | decoder := base64.NewDecoder(base64.StdEncoding, &buf) 7 | decoder.Read(decoded) 8 | return decoded 9 | } 10 | 11 | func Encode(raw []byte) []byte { 12 | var encoded bytes.Buffer 13 | encoder := base64.NewEncoder(base64.StdEncoding, &encoded) 14 | encoder.Write(raw) 15 | encoder.Close() 16 | return encoded.Bytes() 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /go源码分析/内存管理/testmap/testmap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strconv" 5 | "math" 6 | "fmt" 7 | ) 8 | 9 | type info struct { 10 | province string 11 | city string 12 | lat float64 13 | lng float64 14 | } 15 | func main() { 16 | m:=make(map[int64]info) 17 | for i :=0;i<1000*1000*10;i++{ 18 | m[int64(i)]=info{ 19 | strconv.Itoa(i), 20 | strconv.Itoa(i), 21 | math.Sin(float64(i)), 22 | math.Cos(float64(i)), 23 | } 24 | } 25 | print("ok") 26 | for{ 27 | fmt.Scan() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /基本语言知识/基本数据类型.md: -------------------------------------------------------------------------------- 1 | # go基本数据类型 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "math/cmplx" 9 | ) 10 | 11 | var ( 12 | ToBe bool = false 13 | MaxInt uint64 = 1<<64 - 1 14 | z complex128 = cmplx.Sqrt(-5 + 12i) 15 | ) 16 | 17 | func main() { 18 | const f = "%T(%v)\n" 19 | fmt.Printf(f, ToBe, ToBe) 20 | fmt.Printf(f, MaxInt, MaxInt) 21 | fmt.Printf(f, z, z) 22 | } 23 | ``` 24 | 25 | output 26 | ``` 27 | bool(false) 28 | uint64(18446744073709551615) 29 | complex128((2+3i)) 30 | ``` -------------------------------------------------------------------------------- /基本语言知识/时间类型/comparison.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // utc life 11 | loc, _ := time.LoadLocation("UTC") 12 | 13 | // setup a start and end time 14 | createdAt := time.Now().In(loc).Add(1 * time.Hour) 15 | expiresAt := time.Now().In(loc).Add(4 * time.Hour) 16 | 17 | // get the diff 18 | diff := expiresAt.Sub(createdAt) 19 | t := reflect.TypeOf(diff) 20 | 21 | fmt.Println("type", t.Name()) 22 | fmt.Println("Lifespan is %+v", diff) 23 | } 24 | -------------------------------------------------------------------------------- /go源码分析/反射/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type MoeInt int 9 | 10 | func (this *MoeInt) Say() { 11 | fmt.Println(*this) 12 | } 13 | func (this *MoeInt) say() { 14 | fmt.Println(*this) 15 | } 16 | func main() { 17 | //反射类型 18 | var x float64 = 3.4 19 | fmt.Println("type:", reflect.TypeOf(x)) 20 | 21 | //反射函数 22 | var m MoeInt = 4 23 | i := &m 24 | object := reflect.ValueOf(i) 25 | object.MethodByName("Say").Call(nil) 26 | object.MethodByName("say").Call(nil) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /go源码分析/编码解码/json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | 12 | url := "http://localhost:8090/coach?id=1" 13 | 14 | req, _ := http.NewRequest("GET", url, nil) 15 | 16 | res, _ := http.DefaultClient.Do(req) 17 | 18 | defer res.Body.Close() 19 | body, err := ioutil.ReadAll(res.Body) 20 | //fmt.Println(string(body)) 21 | m := make(map[string]interface{}) 22 | err = json.Unmarshal(body, &m) 23 | fmt.Println(err, m) 24 | 25 | } 26 | -------------------------------------------------------------------------------- /基本语言知识/gopackage.md: -------------------------------------------------------------------------------- 1 | 程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它 只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先 将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开 始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数 2 | 3 | ![](/img/gopackage.jpg) 4 | 5 | 6 | 在同一个package中,可以多个文件中定义init方法 7 | 8 | 9 | 在同一个go文件中,可以重复定义init方法 10 | 11 | 12 | 在同一个package中,不同文件中的init方法的执行按照文件名先后执行各个文件中的init方法 13 | 14 | 15 | 在同一个文件中的多个init方法,按照在代码中编写的顺序依次执行不同的init方法 16 | -------------------------------------------------------------------------------- /go源码分析/反射/reflect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | func main() { 10 | js_str := []byte(`{"age":1}`) 11 | var value map[string]interface{} 12 | 13 | json.Unmarshal(js_str, &value) 14 | fmt.Println(reflect.TypeOf(value["age"])) 15 | age := value["age"] 16 | 17 | fmt.Println(value) 18 | fmt.Println(reflect.TypeOf(age)) 19 | fmt.Println(reflect.TypeOf(1)) 20 | } 21 | 22 | ///NND 23 | 24 | // float64 25 | // map[age:1] 26 | // float64 27 | // int 28 | // 默认居然是float64类型 29 | -------------------------------------------------------------------------------- /go源码分析/反射/反射.md: -------------------------------------------------------------------------------- 1 | 2 | #java的反射 3 | 4 | >java的反射机制就是增加程序的灵活性,避免将程序写死到代码里, 5 | 例如: 实例化一个 person()对象, 不使用反射, new person(); 如果想变成 实例化 其他类, 那么必须修改源代码,并重新编译。 6 | 使用反射: class.forName("person").newInstance(); 而且这个类描述可以写到配置文件中,如 **.xml, 这样如果想实例化其他类,只要修改配置文件的"类描述"就可以了,不需要重新修改代码并编译。 7 | 增加程序的灵活性。 8 | 如struts中。请求的派发控制。 9 | 当请求来到时。struts通过查询配置文件。找到该请求对应的action。已经方法。 10 | 然后通过反射实例化action。并调用响应method。 11 | 如果不适用反射,那么你就只能写死到代码里了。 12 | 所以说,一个灵活,一个不灵活。 13 | 很少情况下是非用反射不可的。大多数情况下反射是为了提高程序的灵活性。 14 | 因此一般框架中使用较多。因为框架要适用更多的情况。对灵活性要求较高。 15 | 16 | # go反射 17 | go反射中使用最多的是序列化 -------------------------------------------------------------------------------- /go源码分析/容器类/HashSet.go: -------------------------------------------------------------------------------- 1 | package 容器类 2 | 3 | import "bytes" 4 | 5 | type HashSet struct { 6 | items map[interface{}]struct{} 7 | } 8 | 9 | func NewHashSet() *HashSet{ 10 | var this *HashSet =&HashSet{ 11 | items:make(map[interface{}]struct{}), 12 | } 13 | return this 14 | } 15 | func (this *HashSet)Add(a interface{}) bool{ 16 | _,has:=this.items[a] 17 | if has{ 18 | return false 19 | }else { 20 | this.items[a]=struct{}{} 21 | return true 22 | } 23 | } 24 | func (this *HashSet)String(){ 25 | sb:=bytes.Buffer{} 26 | sb.WriteString() 27 | } -------------------------------------------------------------------------------- /go源码分析/buildin/基础类型.md: -------------------------------------------------------------------------------- 1 | type ComplexType 2 | 3 | type FloatType 4 | 5 | type IntegerType 6 | 7 | type Type 8 | 9 | type Type1 10 | 11 | type bool 12 | 13 | type byte 14 | 15 | type complex128 16 | 17 | type complex64 18 | 19 | type error 20 | 21 | type float32 22 | 23 | type float64 24 | 25 | type int 26 | 27 | type int16 28 | 29 | type int32 30 | 31 | type int64 32 | 33 | type int8 34 | 35 | type rune 36 | 37 | type string 38 | 39 | type uint 40 | 41 | type uint16 42 | 43 | type uint32 44 | 45 | type uint64 46 | 47 | type uint8 48 | 49 | type uintptr -------------------------------------------------------------------------------- /go源码分析/并发/map_rwmutex_r.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var m map[string]interface{} 9 | 10 | func main() { 11 | m = make(map[string]interface{}, 1024) 12 | l := sync.RWMutex{} 13 | go func() { 14 | //write 15 | i := 0 16 | for { 17 | l.RLock() 18 | m["key"] = (i) 19 | fmt.Print("w") 20 | i++ 21 | l.RUnlock() 22 | } 23 | }() 24 | go func() { 25 | //read 26 | i := 0 27 | for { 28 | 29 | i += m["key"].(int) 30 | fmt.Print("r") 31 | 32 | } 33 | }() 34 | for true { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /基本语言知识/流程控制/defer.md: -------------------------------------------------------------------------------- 1 | # defer 2 | defer 语句会将函数推迟到外层函数返回之后执行。 3 | 4 | 推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。 5 | 6 | ``` 7 | package main 8 | 9 | import "fmt" 10 | 11 | func calc(index string,a,b int)int { 12 | ret:=a+b 13 | fmt.Println(index,a,b,ret) 14 | return ret 15 | } 16 | func main() { 17 | a:=1 18 | b:=2 19 | 20 | defer calc("1",a,calc("10",a,b))// "1",1,3("10",1,2,3),4 21 | a=0 22 | defer calc("2",a,calc("20",a,b))//"2",0,2("20",0,2,2),2 23 | b=1 24 | } 25 | ``` 26 | 27 | output 28 | ``` 29 | after recover 30 | recover panic info 31 | before recover 32 | ``` -------------------------------------------------------------------------------- /go源码分析/并发/是否并发冲突测试.go: -------------------------------------------------------------------------------- 1 | // 会导致并发冲突的map访问 2 | // fatal error: concurrent map writes 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | m := make(map[int]string, 1024) 12 | var closures [3]func(int) 13 | for i := 0; i < 3; i++ { 14 | closures[i] = func(v int) { 15 | for { 16 | m[v] += strconv.Itoa(v) 17 | if len(m[v])%1000 == 0 { 18 | fmt.Println(v, len(m[v])) 19 | } 20 | } 21 | } 22 | } 23 | go closures[0](0) 24 | go closures[1](1) 25 | go closures[2](2) 26 | for { 27 | fmt.Scanln() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /go源码分析/并发/sync.RWMUtex.md: -------------------------------------------------------------------------------- 1 | # RWMutex读写锁 2 | 3 | 经常用于读次数远远多于写次数的场景 4 | 5 | func (rw *RWMutex) Lock()  写锁,如果在添加写锁之前已经有其他的读锁和写锁,则lock就会阻塞直到该锁可用,为确保该锁最终可用,已阻塞的 Lock 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定 6 | func (rw *RWMutex) Unlock() 写锁解锁,如果没有进行写锁定,则就会引起一个运行时错误 7 | 8 | func (rw *RWMutex) RLock() 读锁,当有写锁时,无法加载读锁,当只有读锁或者没有锁时,可以加载读锁,读锁可以加载多个,所以适用于"读多写少"的场景 9 | 10 | func (rw *RWMutex)RUnlock() 读锁解锁,RUnlock 撤销单次RLock 调用,它对于其它同时存在的读取器则没有效果。若 rw 并没有为读取而锁定,调用 RUnlock 就会引发一个运行时错误(注:这种说法在go1.3版本中是不对的,例如下面这个例子)。 11 | 12 | 读写锁的写锁只能锁定一次,解锁前不能多次锁定,读锁可以多次,但读解锁次数最多只能比读锁次数多一次,一般情况下我们不建议读解锁次数多余读锁次数 13 | -------------------------------------------------------------------------------- /go源码分析/并发/map_rwmutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var m map[string]interface{} 9 | 10 | func main() { 11 | m = make(map[string]interface{}, 1024) 12 | l := sync.RWMutex{} 13 | go func() { 14 | //write 15 | i := 0 16 | for { 17 | l.Lock() 18 | m["key"] = (i) 19 | fmt.Print("w") 20 | i++ 21 | l.Unlock() 22 | } 23 | }() 24 | go func() { 25 | //read 26 | i := 0 27 | for { 28 | l.Lock() 29 | i += m["key"].(int) 30 | fmt.Print("r") 31 | l.Unlock() 32 | } 33 | }() 34 | for true { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /go源码分析/buildin/内置函数.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/builtin/ 2 | 3 | + func append(slice []Type, elems ...Type) []Type 4 | 5 | + func cap(v Type) int 6 | 7 | + func close(c chan<- Type) 8 | 9 | + func complex(r, i FloatType) ComplexType 10 | 11 | + func copy(dst, src []Type) int 12 | 13 | + func delete(m map[Type]Type1, key Type) 14 | 15 | + func imag(c ComplexType) FloatType 16 | 17 | + func len(v Type) int 18 | 19 | + func make(Type, size IntegerType) Type 20 | 21 | + func new(Type) *Type 22 | 23 | + func panic(v interface{}) 24 | 25 | + func real(c ComplexType) FloatType 26 | 27 | + func recover() interface{} 28 | 29 | -------------------------------------------------------------------------------- /go第三方/mgo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | "log" 6 | ) 7 | 8 | func insertmap(session *mgo.Session, clt *mgo.Collection) { 9 | _row := map[string]interface{}{ 10 | "myd": 234, 11 | "username": map[string]interface{}{"baba": 123}, 12 | } 13 | if err := clt.Insert(_row); err != nil { 14 | log.Printf("insert %v failed: %v\n", _row, err) 15 | } 16 | 17 | } 18 | func main() { 19 | session, err := mgo.Dial("127.0.0.1:27017") 20 | if err != nil { 21 | log.Fatal("无法打开MongoDB!") 22 | return 23 | } 24 | defer session.Close() 25 | clt := session.DB("test").C("test") 26 | //Collontion(session,clt) 27 | insertmap(session, clt) 28 | } 29 | -------------------------------------------------------------------------------- /go源码分析/chan/一个协程处理多个chan/一个协程处理多个chan.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | c1 := make(chan string) 10 | c2 := make(chan string) 11 | 12 | 13 | 14 | go func() { 15 | for true { 16 | time.Sleep(time.Second * 1) 17 | 18 | c1 <- "one" 19 | } 20 | 21 | }() 22 | 23 | go func() { 24 | for true { 25 | time.Sleep(time.Second * 2) 26 | 27 | c2 <- "two" 28 | } 29 | 30 | }() 31 | 32 | 33 | 34 | for true { 35 | 36 | select { 37 | 38 | case msg1 := <-c1: 39 | 40 | fmt.Println("received", msg1) 41 | 42 | case msg2 := <-c2: 43 | 44 | fmt.Println("received", msg2) 45 | 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /go源码分析/值与址/range关键字与slice-map需要注意的.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | pase_student() 10 | } 11 | 12 | type student struct { 13 | Name string 14 | Age int 15 | } 16 | 17 | func pase_student() { 18 | m := make(map[string]*student) 19 | stus := []student{ 20 | {Name: "zhou", Age: 24}, 21 | {Name: "li", Age: 23}, 22 | {Name: "wang", Age: 22}, 23 | } 24 | for _, stu := range stus { 25 | m[stu.Name] = &stu 26 | //这里对&stu,变异后只会指向最后一个对象 27 | } 28 | bs, _ := json.Marshal(m) 29 | fmt.Println(string(bs)) 30 | //{"li":{"Name":"wang","Age":22},"wang":{"Name":"wang","Age":22},"zhou":{"Name":"wang","Age":22}} 31 | } 32 | -------------------------------------------------------------------------------- /XIAOMI/MIHOME.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | print(MIHOME(3, 4, []int{5, 6, 1}, []int{8, 2, 3, 5})) 5 | } 6 | 7 | func Abs(a int) int { 8 | if a < 0 { 9 | return a * -1 10 | } 11 | return a 12 | } 13 | func MIHOME(n, m int, mihome []int, mifans []int) (sum int) { 14 | mihome_fans := make(map[int][]int) 15 | for _, fan := range mifans { 16 | min_home := Abs(mihome[0] - fan) 17 | for _, home := range mihome[1:] { 18 | distance := Abs(home - fan) 19 | if min_home > distance { 20 | min_home = distance 21 | } 22 | } 23 | mihome_fans[min_home] = mihome_fans + distance 24 | } 25 | for k, v := range mihome_fans { 26 | sum += v 27 | } 28 | return 29 | } 30 | -------------------------------------------------------------------------------- /go源码分析/chan/同步/happen_before.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //假设A和B表示一个多线程的程序执行的两个操作。如果A happens-before B,那么A操作对内存的影响 将对执行B的线程(且执行B之前)可见。 8 | //无论使用哪种编程语言,有一点是相同的:如果操作A和B在相同的线程中执行,并且A操作的声明在B之前,那么A happens-before B。 9 | var c = make(chan int, 10) 10 | var a string 11 | 12 | func main(){ 13 | go ff() 14 | <-c // (3) 15 | fmt.Println(a) // (4) 16 | } 17 | 18 | /* 19 | 上述代码可以确保输出"hello, world",因为(1) happens-before (2),(4) happens-after (3),再根据上面的第一条规则(2)是 happens-before (3)的,最后根据happens-before的可传递性,于是有(1) happens-before (4),也就是a = "hello, world" happens-before print(a)。 20 | */ 21 | func ff() { 22 | a = "hello, world" // (1) 23 | c <- 0 // (2) 24 | } -------------------------------------------------------------------------------- /go源码分析/内存管理/sizeof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/timeloveboy/moegraphdb/graphdb" 6 | ) 7 | 8 | func main() { 9 | //ints:=make([]int,8*10000*10000) 10 | // 197mb 11 | //ints:=make([]int64,8*10000*10000) 12 | // 197mb 13 | //ints:=make(map[uint64]uint64,8*10000*10000) 14 | // 594mb 15 | //ints:=make([]graphdb.User,8*10000*10000) 16 | // 590mb 17 | ints := make(map[uint]*graphdb.User) 18 | // 594mb 19 | for k := uint(0); k < 4*1000*10000; k++ { 20 | ints[k] = new(graphdb.User) 21 | ints[k].Uid = k 22 | ints[k].Fans = make(map[uint]byte, 0) 23 | ints[k].Likes = make(map[uint]byte, 0) 24 | } 25 | fmt.Println(len(ints)) 26 | for true { 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /基本语言知识/枚举.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var days = [...]string{ 6 | "Sunday", 7 | "Monday", 8 | "Tuesday", 9 | "Wednesday", 10 | "Thursday", 11 | "Friday", 12 | "Saturday", 13 | } 14 | 15 | const ( 16 | WatchState = 1 << iota 17 | MultiState 18 | SubscribeState 19 | MonitorState 20 | ) 21 | 22 | func main() { 23 | var a interface{} 24 | a = days 25 | fmt.Println(a) 26 | switch vtype := a.(type) { 27 | default: 28 | fmt.Println(vtype) 29 | } 30 | fmt.Println() 31 | fmt.Println(len(days)) 32 | 33 | fmt.Println("WatchState", WatchState) 34 | fmt.Println("MultiState", MultiState) 35 | fmt.Println("SubscribeState", SubscribeState) 36 | fmt.Println("MonitorState", MonitorState) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /go源码分析/chan/协程间通信/协程间通信.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | "fmt" 6 | ) 7 | var (sleeptime=time.Second*1) 8 | type Msg struct{ 9 | chanid int 10 | data string 11 | } 12 | 13 | func Sender(msg chan *Msg){ 14 | count:=0 15 | for true{ 16 | count++ 17 | time.Sleep(sleeptime) 18 | msg<-&Msg{count%5,time.Now().String()[0:19]} 19 | } 20 | } 21 | 22 | func Receiver(chanid int,msg chan *Msg) { 23 | for true { 24 | m := <-msg 25 | 26 | fmt.Println(chanid,*m) 27 | } 28 | } 29 | func main() { 30 | Message:=make(chan *Msg) 31 | go Sender(Message) 32 | go Receiver(0,Message) 33 | go Receiver(1,Message) 34 | go Receiver(2,Message) 35 | go Receiver(3,Message) 36 | go Receiver(4,Message) 37 | 38 | for true{} 39 | } 40 | -------------------------------------------------------------------------------- /go源码分析/容器/heap.md: -------------------------------------------------------------------------------- 1 | # https://golang.org/pkg/container/heap/ 2 | 3 | 包堆提供了堆操作为实现heap.Interface任何类型。堆是每个节点在其子树的最小值节点属性的树。 4 | ``` 5 | // An IntHeap is a min-heap of ints. 6 | type IntHeap []int 7 | 8 | func (h IntHeap) Len() int { return len(h) } 9 | func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } 10 | func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 11 | 12 | func (h *IntHeap) Push(x interface{}) { 13 | // Push and Pop use pointer receivers because they modify the slice's length, 14 | // not just its contents. 15 | *h = append(*h, x.(int)) 16 | } 17 | 18 | func (h *IntHeap) Pop() interface{} { 19 | old := *h 20 | n := len(old) 21 | x := old[n-1] 22 | *h = old[0 : n-1] 23 | return x 24 | } 25 | 26 | ``` -------------------------------------------------------------------------------- /go源码分析/chan/selectchantest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/golang/protobuf/proto" 6 | ) 7 | 8 | var chan3 = make(chan int, 10) 9 | var chan4 = make(chan int, 10) 10 | var chs = []chan int{chan3, chan4} 11 | var numbers = []int{1, 2, 3, 4, 5} 12 | 13 | func main() { 14 | select { 15 | case getChan(0) <- getNumber(2): 16 | fmt.Printf("1st case is selected!\n") 17 | case getChan(1) <- getNumber(3): 18 | fmt.Printf("2st case is selected!\n") 19 | default: 20 | fmt.Printf("default!\n") 21 | } 22 | } 23 | 24 | func getNumber(i int) int { 25 | fmt.Printf("numbers[%d]\n", i) 26 | return numbers[i] 27 | proto.Int32() 28 | } 29 | 30 | func getChan(i int) chan int { 31 | fmt.Printf("chs[%d]\n", i) 32 | return chs[i] 33 | 34 | } 35 | -------------------------------------------------------------------------------- /go源码分析/并发/sync.watigroup.md: -------------------------------------------------------------------------------- 1 | # WaitGroup 2 | 3 | 先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。 4 | 5 | Add(delta int) 6 | 7 | Done() 8 | 9 | Wait() 10 | 11 | ``` 12 | package main 13 | 14 | import ( 15 | "fmt" 16 | "sync" 17 | "time" 18 | ) 19 | 20 | func main() { 21 | var wg sync.WaitGroup 22 | wg.Add(20) 23 | for i := 0; i < 10; i = i + 1 { 24 | 25 | go func() { 26 | //wg.Done() 27 | //defer wg.Add(-1) 28 | EchoNumber(i) 29 | }() 30 | } 31 | for i := 0; i < 10; i = i + 1 { 32 | 33 | go func(n int) { 34 | //wg.Done() 35 | //defer wg.Add(-1) 36 | EchoNumber(n) 37 | }(i) 38 | } 39 | 40 | wg.Wait() 41 | } 42 | 43 | func EchoNumber(i int) { 44 | time.Sleep(3e9) 45 | fmt.Println(i) 46 | } 47 | ``` -------------------------------------------------------------------------------- /go源码分析/并发/sync.Once.md: -------------------------------------------------------------------------------- 1 | # sync.Once 2 | 3 | sync.Once.Do(f func())是一个挺有趣的东西,能保证once只执行一次,无论你是否更换once.Do(xx)这里的方法,这个sync.Once块只会执行一次。 4 | 5 | ``` 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | var once sync.Once 16 | 17 | func main() { 18 | 19 | for i, v := range make([]string, 10) { 20 | once.Do(onces) 21 | fmt.Println("count:", v, "---", i) 22 | } 23 | for i := 0; i < 10; i++ { 24 | 25 | go func() { 26 | once.Do(onced) 27 | fmt.Println("213") 28 | }() 29 | } 30 | time.Sleep(4000) 31 | } 32 | func onces() { 33 | fmt.Println("onces") 34 | } 35 | func onced() { 36 | fmt.Println("onced") 37 | } 38 | 39 | ``` 40 | 整个程序,只会执行onces()方法一次,onced()方法是不会被执行的。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《golang从入门到住院》 2 | 3 | 4 | 5 | 开发笔记大致分为3大块内容,分别以难度划分 6 | 7 | ## 1.新手快速上手 8 | [golang安装](https://github.com/golangdeveloper/golang-note/blob/master/golang_linux_install.md) 9 | 10 | [golang IDE vscode](https://github.com/golangdeveloper/golang-note/blob/master/go_vscode.md) 11 | 12 | [golang IDE liteide](https://github.com/golangdeveloper/golang-note/blob/master/liteide_go.md) 13 | 14 | [godoc](https://github.com/golangdeveloper/golang-note/blob/master/gotools.md) 15 | 16 | 17 | 18 | ### go工程管理 19 | [go package](https://github.com/golangdeveloper/golang-note/blob/master/go_package.md) 20 | ## 2.go基本语法知识 21 | 22 | 23 | [值传递与址传递](/基本语言知识/值与址) 24 | 25 | [错误捕获](/基本语言知识/错误捕获) 26 | 27 | [编码解码](/常用包/编码解码) 28 | 29 | ## 3.go核心特色 30 | 31 | [协程与chan](/基本语言知识/chan与goroutine) 32 | 33 | ## [go源码分析](/go源码分析) 34 | 35 | -------------------------------------------------------------------------------- /go源码分析/chan/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type Set struct { 10 | sync.RWMutex 11 | S map[interface{}]struct{} 12 | } 13 | 14 | func (set *Set) Iter2() <-chan interface{} { 15 | ch := make(chan interface{}) 16 | go func() { 17 | defer func() { 18 | r := recover() 19 | if r != nil { 20 | fmt.Println("捕获bug") 21 | } 22 | set.RUnlock() 23 | }() 24 | 25 | set.RLock() 26 | for k := range set.S { 27 | ch <- k 28 | } 29 | close(ch) 30 | }() 31 | return ch 32 | } 33 | 34 | func main() { 35 | s := Set{} 36 | s.S = make(map[interface{}]struct{}) 37 | s.S[1] = struct{}{} 38 | s.S[2] = struct{}{} 39 | 40 | for k := range s.Iter2() { 41 | fmt.Println("---", k) 42 | panic("测试bug") 43 | } 44 | 45 | time.Sleep(3 * time.Second) 46 | } 47 | -------------------------------------------------------------------------------- /go源码分析/协程栈/README.md: -------------------------------------------------------------------------------- 1 | ## 栈初始化 2 | 3 | + 主协程初始化 4 | 5 | Golang的主协程指的是运行main函数的协程,而子协程指的是在程序运行过程中由主协程创建的协程。每个线程(m)只会有一个主协程,而子协程可能会有很多很多。 6 | 子协程和主协程在概念和内部实现上几乎没有任何区别,唯一的不同在于它们的初始栈大小不同。 7 | 我们先看看测试过程中生成的主协程堆栈示例。我测试代码中就生成了一个主协程,通过反汇编代码看到他的样子大概如下: 8 | 9 | 在go1.5.1版本中,_StackMin大小被定义为2048(而在1.3.2版本中该值还是8192),也即每个协程的初始堆栈大小为2KB,相当小了。缩小该值的好处是即使创建了很多的协程也不会导致内存使用的急剧增长。 10 | 另外,在协程栈空间被分配出来后,还需要作一些其他的初始化,主要是协程栈顶的设置以及堆栈保护的设置。 11 | 栈顶的设置方法比较简单,将当前栈的起始地址减去参数占用的空间即可(注意栈是从高地址向低地址延伸的)。 12 | 栈保护的设置指的是设置一个临界点,当sp到达该临界点时认为栈空间可能会不足,需要进行栈扩容。当前版本的协程栈保护大小事640B。 13 | 14 | ## 堆栈扩容 15 | 16 | + 栈扩容 17 | 18 | 协程堆栈扩容 19 | 20 | 协程栈详细布局 21 | 22 | 我们前面说到,在创建一个协程时就为其创建了一个初始的栈,用来执行函数调用。协程栈的大概布局情况如下: 23 | 24 | 25 | + 栈空间扩容 26 | 27 | 对协程的栈进行扩容必然是原有堆栈空间不足,因此,我们首先需要切换到该线程的堆栈上来调用扩容函数。否则就变成了鸡生蛋和蛋生鸡的问题了:要调用新函数来进行栈扩容,而调用新函数又需要新的栈。 28 | 其次,在新的栈空间申请成功后,我们还需要将现有栈的内容全部拷贝过去。拷贝完成后还得继续现有的函数流程走下去(我们需要能够从线程堆栈切换回协程堆栈)。因此,在调用扩容函数时需要将一些当前的运行环境保存下来。 -------------------------------------------------------------------------------- /go源码分析/内存管理/README.md: -------------------------------------------------------------------------------- 1 | ## Stack内存管理 2 | 3 | 介绍 4 | 5 | 要启动go协程,必须要为其准备栈空间,用来存储函数内变量、执行函数调用等。在go协程退出后,其占用的stack内存也会随之一同释放。 6 | 实际应用中协程的启动、退出可能会比较频繁,runtime必须要做点什么来保证启动、销毁协程的代价尽量小。而申请、释放stack空间所需内存则是一个比较大的开销,因此,go runtime采用了stack cache pool来缓存一定数量的stack memory。申请时从stack cache pool分配,释放时首先归还给stack cache pool。 7 | 主要思想 8 | 9 | stack cache pool的主要思想是按照固定大小划分成多级:每级别其实是一个空闲stack队列:最小的stack size是_FixedStack=2KB。级别之间的大小按照2倍的关系递增。 10 | 同时为了效率考虑,除了全局的stack cache pool外,每个线程m还有自己的stack cache。这样,线程在分配的时候可以优先从自己的stack cache中查找,提高效率。 11 | 初始时,stack cache pool为空:当有stack分配需求时,首先向os申请一块较大的内存,将其按照该级别的stack大小切割后放在空闲stack列表上,然后再从该空闲stack列表上分配。主要结构如下: 12 | 13 | 14 | ## 核心数据结构 15 | 16 | Go内存管理模块的核心数据结构比较少: 17 | mheap:管理全局的从os申请的虚拟内存空间; 18 | mspan:将mheap按照固定大小切分而成的细粒度的内存区块,每个区块映射了虚拟内存中的若干连续页面,页大小由Go内部定义; 19 | mcache:与线程相关缓存,该结构的存在是为了减少内存分配时的锁操作,优化内存分配性能。 20 | mcentral:集中内存池,线程在本地分配失败后,尝试向mcentral申请,如果mcentral也没有资源,则尝试向mheap分配。 -------------------------------------------------------------------------------- /go源码分析/加密/hmac.md: -------------------------------------------------------------------------------- 1 | # hmac 2 | 3 | HMAC的定义 4 | 5 | 定义HMAC需要一个加密用散列函数(表示为H)和一个密钥K。我们假设H是 6 | 一个将数据块用一个基本的迭代压缩函数来加密的散列函数。我们用B来表示数据块 7 | 的字长。(以上说提到的散列函数的分割数据块字长B=64),用L来表示散列函数的 8 | 输出数据字长(MD5中L=16,SHA—1中L=20)。鉴别密钥的长度可以是小于等于数 9 | 据块字长的任何正整数值。应用程序中使用的密钥长度若是比B大,则首先用使用散列 10 | 函数H作用于它,然后用H输出的L长度字符串作为在HMAC中实际使用的密钥。 11 | 一般情况下,推荐的最小密钥K长度是L个字长。(与H的输出数据长度相等)。更详 12 | 细的信息参见第三部分。 13 | 我们将定义两个固定且不同的字符串ipad,opad: 14 | (‘i','o'标志内部与外部) 15 | ipad = the byte 0x36 repeated B times 16 | opad = the byte 0x5C repeated B times. 17 | 计算‘text'的HMAC: 18 | H( K XOR opad, H(K XOR ipad, text)) 19 | 即为以下步骤: 20 | 21 | (1) 在密钥K后面添加0来创建一个子长为B的字符串。(例如,如果K的字长是20 22 | 字节,B=60字节,则K后会加入44个零字节0x00) 23 | 24 | (2) 将上一步生成的B字长的字符串与ipad做异或运算。 25 | 26 | (3) 将数据流text填充至第二步的结果字符串中。 27 | 28 | (4) 用H作用于第三步生成的数据流。 29 | 30 | (5) 将第一步生成的B字长字符串与opad做异或运算。 31 | 32 | (6) 再将第四步的结果填充进第五步的结果中。 33 | 34 | (7) 用H作用于第六步生成的数据流,输出最终结果 -------------------------------------------------------------------------------- /基本语言知识/json_map_string.md: -------------------------------------------------------------------------------- 1 | # json map string byte[]格式互转 2 | 3 | 这里使用的原生json库 4 | 5 | ``` 6 | import ( 7 | "encoding/json" 8 | ) 9 | 10 | func main(){ 11 | jsonStr :="{ 12 | "pub": "2013-06-29 22:59", 13 | "name": "南宁", 14 | "wind": { 15 | "chill": 81, 16 | "direction": 140, 17 | "speed": 7 18 | }, 19 | "astronomy": { 20 | "sunrise": "6:05", 21 | "sunset": "19:34" 22 | }, 23 | "atmosphere": { 24 | "humidity": 89, 25 | "visibility": 6.21, 26 | "pressure": 29.71, 27 | "rising": 1 28 | }}" 29 | 30 | var dat map[string]interface{} 31 | if err := json.Unmarshal([]byte(jsonStr), &dat); err == nil { 32 | fmt.Println("==============json str转map=================") 33 | fmt.Println(dat) 34 | } 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /XIAOMI/ChildNet.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | fmt.Print(^0) 11 | fmt.Println("ip", IP2int("123.45.234.0")) 12 | fmt.Println(ChildNet(IP2int("123.45.234.0"), IP2int("123.45.234.123"), 24)) 13 | } 14 | func IP2int(ip string) uint { 15 | i := 0 16 | is := strings.Split(ip, ".") 17 | for ind, s := range is { 18 | switch ind { 19 | case 0: 20 | v, _ := strconv.Atoi(s) 21 | i += v 22 | case 1: 23 | v, _ := strconv.Atoi(s) 24 | i += v * 256 25 | case 2: 26 | v, _ := strconv.Atoi(s) 27 | i += v * 256 * 256 28 | case 3: 29 | v, _ := strconv.Atoi(s) 30 | i += v * 256 * 256 * 245 31 | 32 | } 33 | 34 | } 35 | return uint(i) 36 | } 37 | func ChildNet(ip, testip uint, bitlen uint) bool { 38 | bit0s := uint(1 << bitlen) 39 | fmt.Println("bit0s", bit0s) 40 | fmt.Println(ip & bit0s) 41 | fmt.Println(testip & bit0s) 42 | 43 | return ip&bit0s == testip&bit0s 44 | } 45 | -------------------------------------------------------------------------------- /go源码分析/net/goip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "net" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | var get_ip = flag.String("get_ip", "", "external|internal") 13 | 14 | func main() { 15 | fmt.Println("Usage of ./getmyip --get_ip=(external|internal)") 16 | flag.Parse() 17 | if *get_ip == "external" { 18 | get_external() 19 | } 20 | 21 | if *get_ip == "internal" { 22 | get_internal() 23 | } 24 | 25 | } 26 | 27 | func get_external() { 28 | resp, err := http.Get("http://myexternalip.com/raw") 29 | if err != nil { 30 | os.Stderr.WriteString(err.Error()) 31 | os.Stderr.WriteString("\n") 32 | os.Exit(1) 33 | } 34 | defer resp.Body.Close() 35 | io.Copy(os.Stdout, resp.Body) 36 | os.Exit(0) 37 | } 38 | 39 | func get_internal() { 40 | addrs, err := net.InterfaceAddrs() 41 | if err != nil { 42 | os.Stderr.WriteString("Oops:" + err.Error()) 43 | os.Exit(1) 44 | } 45 | for _, a := range addrs { 46 | if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 47 | if ipnet.IP.To4() != nil { 48 | os.Stdout.WriteString(ipnet.IP.String() + "\n") 49 | } 50 | } 51 | } 52 | os.Exit(0) 53 | } 54 | -------------------------------------------------------------------------------- /go源码分析/并发/sync.Mutex.md: -------------------------------------------------------------------------------- 1 | # sync.Mutex 互斥锁 2 | 我们已经看到信道非常适合在各个 Go 程间进行通信。 3 | 4 | 但是如果我们并不需要通信呢?比如说,若我们只是想保证每次只有一个 Go 程能够访问一个共享的变量,从而避免冲突? 5 | 6 | 这里涉及的概念叫做 互斥 (mutual exclusion) ,我们通常使用 互斥锁 (Mutex) 这一数据结构来提供这种机制。 7 | 8 | Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法: 9 | 10 | + Lock 11 | + Unlock 12 | 我们可以通过在代码前调用 Lock 方法,在代码后调用 Unlock 方法来保证一段代码的互斥执行。 参见 Inc 方法。 13 | 14 | 我们也可以用 defer 语句来保证互斥锁一定会被解锁。参见 Value 方法。 15 | 16 | ``` 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "sync" 22 | "time" 23 | ) 24 | 25 | // SafeCounter 的并发使用是安全的。 26 | type SafeCounter struct { 27 | v map[string]int 28 | mux sync.Mutex 29 | } 30 | 31 | // Inc 增加给定 key 的计数器的值。 32 | func (c *SafeCounter) Inc(key string) { 33 | c.mux.Lock() 34 | // Lock 之后同一时刻只有一个 goroutine 能访问 c.v 35 | c.v[key]++ 36 | c.mux.Unlock() 37 | } 38 | 39 | // Value 返回给定 key 的计数器的当前值。 40 | func (c *SafeCounter) Value(key string) int { 41 | c.mux.Lock() 42 | // Lock 之后同一时刻只有一个 goroutine 能访问 c.v 43 | defer c.mux.Unlock() 44 | return c.v[key] 45 | } 46 | 47 | func main() { 48 | c := SafeCounter{v: make(map[string]int)} 49 | for i := 0; i < 1000; i++ { 50 | go c.Inc("somekey") 51 | } 52 | 53 | time.Sleep(time.Second) 54 | fmt.Println(c.Value("somekey")) 55 | } 56 | 57 | ``` -------------------------------------------------------------------------------- /go第三方/mgo/mongoapp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gopkg.in/mgo.v2" 6 | "gopkg.in/mgo.v2/bson" 7 | "log" 8 | "math/rand" 9 | "sync" 10 | ) 11 | 12 | func init() { 13 | log.SetFlags(log.Lshortfile | log.LstdFlags) 14 | } 15 | 16 | func getNextSeq(session *mgo.Session) int { 17 | counter := session.DB("dbname").C("counter") 18 | cid := "counterid" 19 | 20 | change := mgo.Change{ 21 | Update: bson.M{"$inc": bson.M{"seq": 1}}, 22 | Upsert: true, 23 | ReturnNew: true, 24 | } 25 | doc := struct{ Seq int }{} 26 | if _, err := counter.Find(bson.M{"myd": cid}).Apply(change, &doc); err != nil { 27 | panic(fmt.Errorf("get counter failed:", err.Error())) 28 | } 29 | log.Println("seq:", doc) 30 | return doc.Seq 31 | 32 | } 33 | func Collontion(session *mgo.Session, clt *mgo.Collection) { 34 | wg := sync.WaitGroup{} 35 | // 创建10个 go routine模拟多线程环境 36 | for i := 0; i < 10; i++ { 37 | wg.Add(1) 38 | go func(i int) { 39 | _row := map[string]interface{}{ 40 | "myd": getNextSeq(session), 41 | "username": fmt.Sprintf("name%2d", i), 42 | "telephone": fmt.Sprintf("tel%4d", rand.Int63n(1000))} 43 | if err := clt.Insert(_row); err != nil { 44 | log.Printf("insert %v failed: %v\n", _row, err) 45 | } else { 46 | log.Printf("insert: %v success!\n", _row) 47 | } 48 | wg.Done() 49 | }(i) 50 | } 51 | wg.Wait() 52 | } 53 | -------------------------------------------------------------------------------- /go源码分析/net/README.md: -------------------------------------------------------------------------------- 1 | ## net 2 | 3 | 编程接口 4 | ``` 5 | func Listen(net, laddr string) (Listener, error) 6 | func (*TCPListener) Accept (c Conn, err error) 7 | func (c *conn) Read(b []byte) (int, error) 8 | func (c *conn) Write(b []byte) (int, error) 9 | ``` 10 | 内部数据结构 11 | 12 | Listener 和 TCPListener 13 | 14 | 简单来说,一个是接口,一个是具体实现。因为golang支持tcp、udp等各种协议,天然使用golang的interface。 15 | Listener定义了针对socket操作的各种接口: 16 | ``` 17 | type Listener interface { 18 | Accept() (c Conn, err error) 19 | Close() error 20 | Addr() Addr 21 | } 22 | ``` 23 | TCPListener则定义了tcp协议需要使用的数据结构 24 | ``` 25 | type TCPListener struct { 26 | fd *netFD 27 | } 28 | ``` 29 | netFD是golang网络库最核心数据结构,贯穿了golang网络库的所有API,它对底层的socket进行封装,屏蔽了不同os的网络实现。我们接下来会单独分析该数据结构。 30 | TCPListener中的fd是与监听套接字关联的socket。 31 | Conn和TCPConn 32 | 33 | Conn与TCPConn的关系类似Listener与TCPListener。也是抽象与具象的关系。 34 | type TCPConn struct { 35 | conn 36 | } 37 | type conn struct { 38 | fd *netFD 39 | } 40 | netFD 41 | 42 | 这个结构太关键了,说它是golang网络库最核心数据结构一点也不为过。所有golang网络接口最终都会转化为对该结构的方法。 43 | ``` 44 | // Network file descriptor. 45 | type netFD struct { 46 | // 不太明白这个mutex的作用 47 | fdmu fdMutex 48 | // 该socket相关的fd 49 | sysfd int 50 | family int 51 | sotype int 52 | isConnected bool 53 | net string 54 | laddr Addr 55 | raddr Addr 56 | // wait server 57 | // 与epoll相关结构 58 | pd pollDesc 59 | } 60 | ``` 61 | 而这个结构中最重要的又是最后一个成员pd,golang网络库实现高并发全靠它了。 62 | ``` 63 | type pollDesc struct { 64 | runtimeCtx uintptr 65 | } 66 | ``` 67 | 大致梳理了golang网络库中的几个基本数据结构,接下来我们就可以深入到内部实现流程了。 -------------------------------------------------------------------------------- /go源码分析/并发/SafeMap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type SafeMap struct { 8 | lock *sync.RWMutex 9 | sm map[interface{}]interface{} 10 | } 11 | 12 | func SafeMap() *SafeMap { 13 | return &SafeMap{ 14 | lock: new(sync.RWMutex), 15 | sm: make(map[interface{}]interface{}), 16 | } 17 | } 18 | 19 | //Get from maps return the k's value 20 | func (m *SafeMap) Get(k interface{}) interface{} { 21 | m.lock.RLock() 22 | defer m.lock.RUnlock() 23 | if val, ok := m.sm[k]; ok { 24 | return val 25 | } 26 | return nil 27 | } 28 | 29 | // Maps the given key and value. Returns false 30 | // if the key is already in the map and changes nothing. 31 | func (m *SafeMap) Set(k interface{}, v interface{}) bool { 32 | m.lock.Lock() 33 | defer m.lock.Unlock() 34 | if val, ok := m.sm[k]; !ok { 35 | m.sm[k] = v 36 | } else if val != v { 37 | m.sm[k] = v 38 | } else { 39 | return false 40 | } 41 | return true 42 | } 43 | 44 | // Returns true if k is exist in the map. 45 | func (m *SafeMap) Check(k interface{}) bool { 46 | m.lock.RLock() 47 | defer m.lock.RUnlock() 48 | if _, ok := m.sm[k]; !ok { 49 | return false 50 | } 51 | return true 52 | } 53 | 54 | func (m *SafeMap) Delete(k interface{}) { 55 | m.lock.Lock() 56 | defer m.lock.Unlock() 57 | delete(m.sm, k) 58 | } 59 | 60 | //Get from maps return the k's value 61 | func (m *SafeMap) Keys() (keys []interface{}) { 62 | m.lock.RLock() 63 | defer m.lock.RUnlock() 64 | keys = make([]interface{}, len(m.sm)) 65 | i := 0 66 | for key, _ := range m.sm { 67 | keys[i] = key 68 | i++ 69 | } 70 | return 71 | } 72 | -------------------------------------------------------------------------------- /go第三方/SummerApp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/cocotyty/summer" 5 | "fmt" 6 | ) 7 | 8 | func init() { 9 | summer.Toml(` 10 | [printer] 11 | prefix="[PRINT]"`) 12 | summer.Put(&A{}) 13 | summer.Add("lay", &B{}) 14 | summer.Put(&Cat{}) 15 | summer.Put(&Printer{}) 16 | summer.Start() 17 | } 18 | 19 | func main() { 20 | a := summer.GetStoneWithName("a").(*A) 21 | a.Call() 22 | } 23 | 24 | type A struct { 25 | // $ means you want to get a stone's field , it happened usually after stones inited 26 | BoyName string `sm:"$.lay.Name"` 27 | B *B `sm:"lay"` 28 | // yes,we support interface ,tag is stone's name 29 | C C `sm:"cat"` 30 | } 31 | 32 | func (a *A)Call() { 33 | a.C.Print() 34 | fmt.Println("hi ,I am A", "bodys name:", a.BoyName) 35 | fmt.Println(a.B) 36 | } 37 | 38 | type B struct { 39 | Name string 40 | } 41 | 42 | func (this *B)Init() { 43 | this.Name = "Boy!" 44 | } 45 | 46 | type C interface { 47 | Print() 48 | } 49 | type Printer struct { 50 | // if you already set the toml plugin config, you can use the # ,to get value from toml, 51 | // # is toml plugin's name 52 | // toml plugin will work after directly dependency resolved,before init 53 | Prefix string `sm:"#.printer.prefix"` 54 | } 55 | 56 | func (printer *Printer)Print(str string) { 57 | fmt.Println(printer.Prefix + str) 58 | } 59 | 60 | type Cat struct { 61 | // * is mostly used tag,summer will find by the field's name or the field's type or both 62 | Printer *Printer `sm:"*"` 63 | } 64 | 65 | func (c *Cat)Ready() { 66 | fmt.Println("my name is cat,i am ready.") 67 | } 68 | func (c *Cat)Print() { 69 | c.Printer.Print("Little Cat") 70 | } -------------------------------------------------------------------------------- /go源码分析/并发/README.md: -------------------------------------------------------------------------------- 1 | 1 为什么Golang需要调度器? 2 | Goroutine的引入是为了方便高并发程序的编写。 一个Goroutine在进行阻塞操作(比如系统调用)时,会把当前线程中的其他Goroutine移交到其他线程中继续执行, 从而避免了整个程序的阻塞。 3 | 4 | 由于Golang引入了垃圾回收(gc),在执行gc时就要求Goroutine是停止的。通过自己实现调度器,就可以方便的实现该功能。 通过多个Goroutine来实现并发程序,既有异步IO的优势,又具有多线程、多进程编写程序的便利性。 5 | 6 | 引入Goroutine,也意味着引入了极大的复杂性。一个Goroutine既要包含要执行的代码, 又要包含用于执行该代码的栈和PC、SP指针。 7 | 8 | 2 调度器解决了什么问题? 9 | 2.1 栈管理 10 | 既然每个Goroutine都有自己的栈,那么在创建Goroutine时,就要同时创建对应的栈。 Goroutine在执行时,栈空间会不停增长。 栈通常是连续增长的,由于每个进程中的各个线程共享虚拟内存空间,当有多个线程时,就需要为每个线程分配不同起始地址的栈。 这就需要在分配栈之前先预估每个线程栈的大小。如果线程数量非常多,就很容易栈溢出。 11 | 12 | 为了解决这个问题,就有了Split Stacks技术: 创建栈时,只分配一块比较小的内存,如果进行某次函数调用导致栈空间不足时,就会在其他地方分配一块新的栈空间。 新的空间不需要和老的栈空间连续。函数调用的参数会拷贝到新的栈空间中,接下来的函数执行都在新栈空间中进行。 13 | 14 | Golang的栈管理方式与此类似,但是为了更高的效率,使用了连续栈 (Golang连续栈) 实现方式也是先分配一块固定大小的栈,在栈空间不足时,分配一块更大的栈,并把旧的栈全部拷贝到新栈中。 这样避免了Split Stacks方法可能导致的频繁内存分配和释放。 15 | 16 | 2.2 抢占式调度 17 | Goroutine的执行是可以被抢占的。如果一个Goroutine一直占用CPU,长时间没有被调度过, 就会被runtime抢占掉,把CPU时间交给其他Goroutine。 18 | 19 | 3 调度器的设计 20 | Golang调度器引入了三个结构来对调度的过程建模: 21 | 22 | G 代表一个Goroutine; 23 | M 代表一个操作系统的线程; 24 | P 代表一个CPU处理器,通常P的数量等于CPU核数(GOMAXPROCS)。 25 | 三者都在runtime2.go中定义,他们之间的关系如下: 26 | 27 | G需要绑定在M上才能运行; 28 | M需要绑定P才能运行; 29 | 程序中的多个M并不会同时都处于执行状态,最多只有GOMAXPROCS个M在执行。 30 | 早期版本的Golang是没有P的,调度是由G与M完成。 这样的问题在于每当创建、终止Goroutine或者需要调度时,需要一个全局的锁来保护调度的相关对象(sched)。 全局锁严重影响Goroutine的并发性能。 (Scalable Go Scheduler) 31 | 32 | 通过引入P,实现了一种叫做work-stealing的调度算法: 33 | 34 | 每个P维护一个G队列; 35 | 当一个G被创建出来,或者变为可执行状态时,就把他放到P的可执行队列中; 36 | 当一个G执行结束时,P会从队列中把该G取出;如果此时P的队列为空,即没有其他G可以执行, 就随机选择另外一个P,从其可执行的G队列中偷取一半。 37 | 该算法避免了在Goroutine调度时使用全局锁。 38 | 39 | 4 调度器的实现 40 | 4.1 schedule()与findrunnable()函数 41 | Goroutine调度是在P中进行,每当runtime需要进行调度时,会调用schedule()函数, 该函数在proc1.go文件中定义。 42 | 43 | schedule()函数首先调用runqget()从当前P的队列中取一个可以执行的G。 如果队列为空,继续调用findrunnable()函数。findrunnable()函数会按照以下顺序来取得G: 44 | 45 | 调用runqget()从当前P的队列中取G(和schedule()中的调用相同); 46 | 调用globrunqget()从全局队列中取可执行的G; 47 | 调用netpoll()取异步调用结束的G,该次调用为非阻塞调用,直接返回; 48 | 调用runqsteal()从其他P的队列中“偷”。 49 | 如果以上四步都没能获取成功,就继续执行一些低优先级的工作: 50 | 51 | 如果处于垃圾回收标记阶段,就进行垃圾回收的标记工作; 52 | 再次调用globrunqget()从全局队列中取可执行的G; 53 | 再次调用netpoll()取异步调用结束的G,该次调用为阻塞调用。 54 | 如果还没有获得G,就停止当前M的执行,返回findrunnable()函数开头重新执行。 如果findrunnable()正常返回一个G,shedule()函数会调用execute()函数执行该G。 execute()函数会调用gogo()函数(在汇编源文件asm_XXX.s中定义,XXX代表系统架构),gogo() 函数会从G.sched结构中恢复出G上次被调度器暂停时的寄存器现场(SP、PC等),然后继续执行。 -------------------------------------------------------------------------------- /go源码分析/内存管理/gc/GC.md: -------------------------------------------------------------------------------- 1 | 2 | # 垃圾收集器(GC) 3 | 4 | GC与增变线程同时运行,类型准确(又精确),允许多个 5 | GC线程并行运行。这是一个并发的标记和扫描,使用写屏障。它是 6 | 非代和压缩分配使用每个P分配的大小分离来完成 7 | 在最常的情况下,尽量减少碎片,同时消除锁定。 8 | 9 | 算法分成几个步骤。 10 | 这是对正在使用的算法的高级描述。有关GC的一个好的概述 11 | 开始的地方是Richard Jones的gchandbook.org。 12 | 13 | 算法的智力遗产包括Dijkstra的即时算法,请参阅 14 | Edsger W. Dijkstra,Leslie Lamport,A. J. Martin,C. S. Scholten和E. F. M. Steffens。 1978年。 15 | 即时垃圾收集:合作练习。 COMMUN。 ACM 21,11(1978年11月), 16 | 966-975。 17 | 对于期刊质量的证明,这些步骤是完整的,正确的,并终止见 18 | Hudson,R.和Moss,J.E.在不停止世界的情况下复制垃圾收集。 19 | 并发和计算:实践和经验15(3-5),2003。 20 | 21 | GC执行扫描终止。 22 | 23 | 一个。阻止世界。这导致所有的Ps达到GC安全点。 24 | 25 | b。扫除任何未扫描的跨度。只有没有扫描的跨度 26 | 这个GC周期在预期的时间之前被迫。 27 | 28 | 2. GC执行“标记1”子阶段。在这个分阶段,Ps是 29 | 允许本地缓存部分工作队列。 30 | 31 | 一个。通过将gcphase设置为_GCmark来准备标记阶段 32 | (来自_GCoff),启用写屏障,启用增变器 33 | 帮助,排队根标记工作。没有任何物体可能 34 | 扫描直到所有的Ps都启用了写屏障,这是 35 | 使用STW完成 36 | 37 | b。开始世界。从这一点来说,GC工作是通过标记完成的 38 | 由调度员开始的工作人员和按照执行的辅助工作 39 | 分配的一部分。写屏障遮蔽了两者 40 | 覆盖指针和任何指针的新指针值 41 | 写入(有关详细信息,请参阅mbarrier.go)。新分配的对象 42 | 立即被标记为黑色。 43 | 44 | C。 GC执行根标记作业。这包括扫描所有 45 | /堆栈,着色所有全局变量,并着色任何堆指针 46 | 堆外运行时数据结构。扫描一个堆栈会停止一个 47 | goroutine,在栈上找到指针,然后 48 | 恢复goroutine。 49 | 50 | d。 GC排出灰色物体的工作队列,扫描每个灰色 51 | 对象为黑色,并在对象中找到所有指针 52 | (这又可以将这些指针添加到工作队列中)。 53 | 54 | 一旦全局工作队列为空(但是本地工作队列缓存) 55 | 可能仍然包含工作),GC执行“标记2”子阶段。 56 | 57 | 一个。 GC停止所有工作,禁用本地工作队列缓存, 58 | 将每个P的本地工作队列缓存刷新到全局工作队列中 59 | 缓存,并重新启用工人。 60 | 61 | b。 GC再次排空工作队列,如上面的2d所示。 62 | 63 | 4.一旦工作队列为空,GC会执行标记终止。 64 | 65 | 一个。阻止世界。 66 | 67 | b。将gcphase设置为_GCmarktermination,并禁用worker和 68 | 助攻 69 | 70 | C。从工作队列中排除剩余的工作(通常在那里) 71 | 将不会)。 72 | 73 | d。执行其他内务管理,例如冲洗微软。 74 | 75 | GC执行扫描阶段。 76 | 77 | 一个。通过将gcphase设置为_GCoff来准备扫描阶段, 78 | 设置扫描状态并禁用写屏障。 79 | 80 | b。开始世界。从这点开始,新分配的对象 81 | 是白色的,如果需要,在使用之前分配扫描。 82 | 83 | C。 GC在后台进行并发扫描并作出响应 84 | 分配。请看下面的描述。 85 | 86 | 当分配完成后,重播序列 87 | 从上面的1开始请参阅下面的GC率的讨论。 88 | 89 | 并发扫描 90 | 91 | 扫描阶段与正常程序执行同时进行。 92 | 堆是一个跨越跨度懒惰(当一个goroutine需要另一个跨度) 93 | 并发地在后台goroutine(这有助于不受CPU限制的程序)。 94 | 在STW标记结束时,所有跨度都被标记为“需要扫描”。 95 | 96 | 后台扫除程序goroutine简单地扫描一个接一个。 97 | 98 | 为了避免请求更多的操作系统内存,而有未扫描的跨度,当一个 99 | / goroutine需要另一个跨度,它首先试图回收这么多的内存 100 | 通过扫描当一个goroutine需要分配一个新的小对象跨度时, 101 | /扫描小对象跨度为相同的对象大小,直到它至少释放 102 | 一个对象当一个goroutine需要从堆中分配大对象跨度时, 103 | /它扫描跨越,直到它至少释放堆到多个页面。有 104 | 一个这样做可能不够的情况:如果一个goroutine扫除并释放两个 105 | 不相邻的单页跨度到堆,它将分配一个新的两个 106 | 107 | /opt/go/src/runtime/mgc.go 108 | 109 | /opt/go/src/runtime/mgclarge.go 110 | 111 | /opt/go/src/runtime/mgcmark.go 112 | 113 | /opt/go/src/runtime/mgcsweep.go 114 | 115 | /opt/go/src/runtime/mgcsweepbuf.go 116 | 117 | /opt/go/src/runtime/mgcwork.go --------------------------------------------------------------------------------