type IF interface { // 只有行为 getName() string } type Human struct { // 只有属性 firstName, lastName string } type Car struct { // 只有属性 factory, model string }
func(receiver *Server) StartTLS() { if receiver.URL != "" { panic("Server started already!") } }
funcmain() { server := Server{URL: "zhongmingmao.me"} server.StartTLS() }
反射
reflect.TypeOf():返回被检查对象的类型
reflect.ValueOf():返回被检查对象的值
1 2 3 4 5 6 7 8 9 10 11 12
m := make(map[string]string, 10) m["name"] = "zhongmingmao"
// func TypeOf(i interface{}) Type // type Type interface t := reflect.TypeOf(m) fmt.Printf("%T, %s\n", t, t) // *reflect.rtype, map[string]string
// func ValueOf(i interface{}) Value // type Value struct v := reflect.ValueOf(m) fmt.Printf("%T, %s\n", v, v) // reflect.Value, map[name:zhongmingmao]
func(receiver student) GetAge() int { return receiver.age }
funcmain() { s := student{name: "A", age: 1}
t := reflect.TypeOf(s) for i := 0; i < t.NumMethod(); i++ { method := t.Method(i) fmt.Printf("Method[%d]: %T, %v\n", i, method, method.Name) } // Method[0]: reflect.Method, GetAge // Method[1]: reflect.Method, GetName
v := reflect.ValueOf(s) for i := 0; i < v.NumField(); i++ { field := v.Field(i) fmt.Printf("Field[%d]: %T, %v\n", i, field, field) } // Field[0]: reflect.Value, A // Field[1]: reflect.Value, 1 }
// 解析任意对象 var obj interface{} if err := json.Unmarshal(bytes, &obj); err == nil { // Type assertions: v, ok = x.(T) // If T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T. // If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T. if m, ok := obj.(map[string]interface{}); ok { for key, v := range m { // Type switches switch value := v.(type) { casestring: fmt.Printf("key: %v, value: %v, type: %T\n", key, value, value) caseinterface{}: fmt.Printf("key: %v, value: %v, type: %T\n", key, value, value) default: fmt.Printf("key: %v, value: %v, type: %T\n", key, value, value) } } // key: name, value: z, type: string // key: class, value: map[Name:c], type: map[string]interface {} } } } }
lock := sync.Mutex{} for i := 0; i < 3; i++ { i := i gofunc() { // 使用闭包解决死锁,保证 Go Routine 结束的时候执行 defer 里面的解锁逻辑 defer lock.Unlock() lock.Lock() println(i) }() }
Panic & Recover
panic
在系统出现不可恢复错误时主动调用 panic,使当前线程直接 Crash
defer
保证执行,并把控制权交还给接收到 panic 的函数调用者
recover
函数从 panic 或者错误场景中恢复
1 2 3 4 5 6 7 8 9 10
// defer + recover deferfunc() { fmt.Println("defer func is called") if err := recover(); err != nil { fmt.Println(err) } }() panic("a panic is triggered") // defer func is called // a panic is triggered
并发
并发 & 并行
并发(单核):多个事件间隔发生
并行(多核):多个事件同时发生
协程
进程
分配系统资源(CPU 时间、内存等)的基本单位
有独立的内存空间、切换开销大
线程
线程是进程的一个执行流,是 CPU 调度并能独立运行的基本单位
同一进程中的多线程共享内存空间,线程切换代价小
线程间通信比进程间通信更方便
从内核层面来看,线程其实也是一种特殊的进程
与父进程共享了打开的文件和文件系统信息,共享了地址空间和信号处理函数
协程
协程是 Go 中的轻量级线程实现
Go 在 Runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,从语言层面支持了协程
当遇到长时间执行或者系统调用时,会主动把当前 goroutine 的 CPU 转让出去
CSP
CSP
Communicating Sequential Process
Communicating:Routine + Channel
Sequential:调度器
描述两个独立的并发实体通过共享的通讯管道 Channel 进行通信的并发模型
在 Go 中,独立的并发实体即 goroutine
goroutine
轻量级线程,并非 OS 的线程,而是将 OS 的线程分段使用,通过调度器实现协作式调度
goroutine 是一种绿色线程,微线程,能够在发现阻塞后启动新的微线程
绿色线程是一种由 Runtime 或 VM 调度,而不是由 OS 调度的线程
channel
类似于 Unix 的 Pipe,用于协程之间的通讯和同步
goroutine 之间虽然解耦,但 goroutine 与 channel 有耦合
Thread & Routine
Thread
Routine
占用内存
8MB
2KB
切换开销
大,涉及模式切换,涉及16个寄存器的刷新
小,涉及3个寄存器的刷新
并发数量
比较有限
GOMAXPROC
Go Routine
1 2 3
for i := 0; i < 10; i++ { go fmt.Println(i) // 启动新协程 }
select { case v := <-ch1: fmt.Printf("select from ch1, v: %v\n", v) case v := <-ch2: fmt.Printf("select from ch2, v: %v\n", v) default: fmt.Println("select default") }
Timeout Channel
time.Ticker 以指定的时间间隔重复地向 Channel C 发送时间值
使用场景:为 Routine 设定超时时间
1 2 3 4 5 6 7 8 9
ch := make(chanint) timer := time.NewTimer(time.Second) select { case <-ch: fmt.Println("received from ch") case <-timer.C: // When the Timer expires, the current time will be sent on C, which C is (<-chan Time) fmt.Println("timeout waiting from channel ch") } // timeout waiting from channel ch
select { case <-timeoutCtx.Done(): time.Sleep(time.Second) println("main process exit!") } // enter default // child process interrupt... // main process exit!