reference from: http://blog.wuxu92.com/
Table of Contents
- 不定參數
- closure
- Error handle
- channel
- 使用channel同步goroutine
- channel directive
- select
- 超時
- non-blocking channel
- range over channel
- Timer & Ticker
- Timer
- Tickers
- worker pool/worker池
- rate-limiting
- rand
- strconv
- url parse
- A Full Example For Polymorphism & Composition
不定參數
1 2 3 4 5 6 7 8 9
| func sum (nums ...int){ total := 0 for _, num := range nums { total += num } return total } nums := []int{1,2,3,4,5} t := sum(nums...)
|
closure
1 2 3 4 5 6 7 8 9 10
| func intSeq() func() int { i := 0 return func() int { i += 1; return i } } next := intSeq() next()
|
Error handle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| type myErr struct { arg int prob string } func (e myErr) Error() string { return fmt.Sprintf("%d - %s", e.arg, e.prob) } type Person struct{ age int } func (p Person)buy(item string) (bool, error) { if p.age < 18 { return false, &myErr{0, "too yong"} } return true, nil } me := Person{10} , e := me.buy("shirt") if me, ok := e.(*myErr); ok { ... }
|
channel
channel預設是blocking的
channel中沒東西recieve的話會block, 若已沒有其他goroutine則會panic
使用channel同步goroutine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func working(flagChan chan bool) { fmt.Println("working on it") time.Sleep(2 * time.Second) fmt.Println("work done") flagChan <- true } func chanSync() { flagChan := make(chan bool, 1) go working(flagChan) done := <- flagChan fmt.Println("sync goroutine output", done) }
|
channel directive
1 2
| func send (flagChan chan<- bool) { ... } func recv (flagChan <-chan bool) { ... }
|
select
select用於從多個channel中輪訓狀態, 從已經準備就緒的channel中接受值並執行相對應代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import ( "math/rand" "time" "strconv" ) func gr1(c chan string) { dur := rand.Intn(300) time.Sleep(time.Millisecond * time.Duration(dur)) c <- "gr1 sleep done " + strconv.Itoa(dur) } func gr2(c chan string) { dur := rand.Intn(400) time.Sleep(time.Millisecond * time.Duration(dur)) c <- "gr2 sleep done " + strconv.Itoa(dur) } func selects() { c1 := make(chan string) c2 := make(chan string) go gr1(c1) go gr1(c1) go gr2(c2) go gr2(c2) for i:=0; i<4; i++ { select { case msg := <-c1: fmt.Println(msg) case msg2 := <-c2: fmt.Println(msg2) } } }
|
超時
若等待超過一定時間沒有resource則執行
1 2 3 4 5 6
| select { case res <- c1 : fmt.Println(res) case <-time.After(time.Seconde * 2) fmt.Println("timeout") }
|
non-blocking channel
所有case的channel都没有就绪的时候执行default
1 2 3 4 5 6 7 8 9
| select { case msg := <-c1: fmt.Println(msg) case msg2 := <-c2: fmt.Println(msg2) default: fmt.Println("select default") }
|
range over channel
对于一个close了得channel,range能自动判断是否遍历结束,但是如果channel没有调用过close,在下面的代码中,会在接受第三个值的时候阻塞(异常退出)
1 2 3 4 5 6 7 8 9
| func rangeChannel() { c := make(chan string, 2) c <- "tomorrow is monday" c <- "fee out" close(c) for str := range c { fmt.Println(str) } }
|
Timer & Ticker
Timer
timer is like a channel
1 2 3 4 5 6
| import "time" ... timer1 := time.NewTimer(time.Second *2) <- timer1.C
|
Tickers
ticker就像打点器一样循环执行某代码
ticker看作一个channel,在初始化时定义一个循环时间,每过一段时间往channel里面塞一个数,然后我们循环去取
1 2 3 4 5 6 7 8 9
| t1 := time.NewTicker(time.Millisecond * 500) go func() { for t := range t1.C { fmt.Println("tick tick @ ", t) } }() time.Sleep(time.Second * 3) t1.Stop() fmt.Println("tick tick stop")
|
worker pool/worker池
可以把一个goroutine看作一个worker。给多个worker传入相同的channel,worker从channel中取任务并处理,主线程往channel中添加任务,这样过个goroutine处理一个任务队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| jobs := make(chan int, 100) result := make(chan int, 100) for w:=0; w<5; w++ { go func(w int, jobs <-chan int, result chan<- int) { for j:= range jobs { fmt.Println("worker", w, "processing on", j) time.Sleep(time.Millisecond * time.Duration(rand.Intn(600))) result <- j * 2 } }(w, jobs, result) } for j:=0; j<10; j++ { jobs <- j } close(jobs) for a :=0; a<10; a++ { <- result } fmt.Println("all work done here")
|
rate-limiting
使用goroutine,channel, ticker合作实现该特性
使用两个channel协同,一个用于处理速率的控制,一个用于请求的缓冲。使用一个goroutine不断的定时填充速率控制goroutine,而请求channel则用一个for-range不停行从里面取请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| rateControlChan := make(chan time.Time, 3) for i:=0; i<3; i++ { rateControlChan <- time.Now() } go func() { for t := range time.Tick(time.Millisecond * 200) { rateControlChan <- t } }() reqChannel := make(chan int, 5) for i:=0; i< 5; i++ { reqChannel <- i } close(reqChannel) for r:= range reqChannel { ht := <- rateControlChan fmt.Println("req", r, "handle at", ht) }
|
rand
1 2 3 4 5 6 7 8
| rs := rand.NewSource(time.Now().UnixNano()) r := rand.New(rs) r.Intn(100) rand.Float64() rand.Int31() rand.Uint32()
|
strconv
1 2 3 4 5 6 7 8 9 10
| func ParseFloat(s string, bitSize int) (f float64, err error) f,_ := strconv.ParseFloat("1.23", 64) // 转换到64位Float,不处理转换的错误 func ParseInt(s string, base int, bitSize int) (i int64, err error)
// 更常用的 k,_ := strconv.Atoi("123") // k=123 _,e := strconv.Atoi("wrongFormat")
|
url parse
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import "net/url" urlStr := "https://gobyexample.com/url-parsing?from=goole#url-parsing" u, err := url.Parse(urlStr) if err != nil { fmt.Println(err) } fmt.Println(u.Scheme,u.Host, u.Path, u.Fragment, u.RawQuery) host, port, _ := net.SplitHostPort(u.Host) user := u.User username := "null" if user != nil { username = user.Username() } fmt.Println("username", username) query, _ := url.ParseQuery(u.RawQuery) fmt.Println(query, query["from"][0])
|
A Full Example For Polymorphism & Composition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package main import ( "fmt" ) type notifier interface { notify() } type user struct { name string email string } type admin struct { user level string } func (u *user) notify() { fmt.Printf("user: Sending user email To %s<%s>\n", u.name, u.email) } func (a *admin) notify() { fmt.Printf("User: Sending Admin Email To %s<%s>\n", a.name, a.email) } func main() { ad := admin{ user: user{ name: "john smith", email: "john@yahoo.com", }, level: "super", } sendNotification(&ad) ad.user.notify() ad.notify() } func sendNotification(n notifier) { n.notify() }
|