這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
1. golang程式已耗用時間顯示
package mainimport ("fmt""time""math/rand")func main(){rand.Seed(time.Now().Unix())var name stringfor i:=0; i<3; i++{name=fmt.Sprintf("go_%02d", i)go runroutine(name, time.Duration(rand.Intn(5))*time.Second)}var input string//for waiting goroutine, unless it exit.fmt.Scanln(&input)fmt.Println("Done")}func runroutine(name string, t time.Duration){t0:=time.Now()fmt.Println(name, " start at ", t0)time.Sleep(t)t1:=time.Now()fmt.Println(name, " end at ", t1)fmt.Println(name, " lasted ", t1.Sub(t0))fmt.Println()}
運行結果:
go_00 start at 2013-12-05 17:22:34.5337149 +0800 +0800go_01 start at 2013-12-05 17:22:34.5367151 +0800 +0800go_02 start at 2013-12-05 17:22:34.5367151 +0800 +0800go_02 end at 2013-12-05 17:22:36.5548305 +0800 +0800go_02 lasted 2.0181154sgo_00 end at 2013-12-05 17:22:37.5558878 +0800 +0800go_00 lasted 3.0221729sgo_01 end at 2013-12-05 17:22:38.5549449 +0800 +0800go_01 lasted 4.0182298sjDone
2. 利用mutex控制goroutine的執行
package mainimport "fmt"import "time"import "math/rand"import "sync"import "runtime"//var total_tickets int32 = 10var mutex = &sync.Mutex{} //可簡寫成:var mutex sync.Mutexfunc sell_tickets(i int, t time.Duration) {var total_tickets int32 = 10for {mutex.Lock()if total_tickets > 0 {time.Sleep(t)total_tickets--fmt.Println("id:", i, " ticket:", total_tickets)}mutex.Unlock()}}func main() {runtime.GOMAXPROCS(4) //我的電腦是4核處理器,所以我設定了4rand.Seed(time.Now().Unix()) //產生隨機種子for i := 0; i < 5; i++ { //並發5個goroutine來賣票go sell_tickets(i, time.Duration(rand.Intn(5))*time.Millisecond)}//等待線程執行完var input stringfmt.Scanln(&input)//fmt.Println(total_tickets, "done") //退出時列印還有多少票}
3. 利用select監聽channel
package main import "time" import "fmt" func main() { //建立兩個channel - c1 c2 c1 := make(chan string) c2 := make(chan string) //建立兩個goruntine來分別向這兩個channel發送資料 go func() { time.Sleep(time.Second * 1) c1 <- "Hello" }() go func() { time.Sleep(time.Second * 1) c2 <- "World" }() //使用select來偵聽兩個channel for { select { case msg1 := <-c1: fmt.Println("received", msg1) case msg2 := <-c2: fmt.Println("received", msg2) case <-time.After(time.Second * 30): fmt.Println("Time Out") break } } }
上面代碼執行time.After時總是報錯:invalid identifier。不知道為什麼。如果改成default,加入sleep和break,由於break寫在最後,導致sleep後繼續監聽而使break永遠也得不到執行。
package mainimport "time"import "fmt"func main() {//建立兩個channel - c1 c2c1 := make(chan string)c2 := make(chan string)//建立兩個goruntine來分別向這兩個channel發送資料go func() {time.Sleep(time.Second * 1)c1 <- "Hello"}()go func() {time.Sleep(time.Second * 1)c2 <- "World"}()//使用select來偵聽兩個channelfor {select {case msg1 := <-c1:fmt.Println("received", msg1)case msg2 := <-c2:fmt.Println("received", msg2)default: //default會導致無阻塞fmt.Println("nothing received!")time.Sleep(time.Second)
//break永遠也不會執行break}}}
關閉channel,總是在發送端關閉:
package mainimport "fmt"import "time"import "math/rand"func main() {channel := make(chan string)rand.Seed(time.Now().Unix())//向channel發送隨機個數的messagego func () {cnt := rand.Intn(10)fmt.Println("message cnt :", cnt)for i:=0; i<cnt; i++{channel <- fmt.Sprintf("message-%2d", i)}close(channel) //關閉Channel}()var more bool = truevar msg stringfor more {select{//channel會返回兩個值,一個是內容,一個是boolcase msg, more = <- channel:if more {fmt.Println(msg)}else{fmt.Println("channel closed!")}}}}
4. golang的定時器
Go語言中可以使用time.NewTimer或time.NewTicker來設定一個定時器,這個定時器會綁定在你的當前channel中,通過channel的阻塞通知機器來通知你的程式。
package mainimport "time"import "fmt"func main() {ticker := time.NewTicker(time.Second)go func() {for t := range ticker.C {fmt.Println(t)}}()//設定一個timer,10鈔後停掉tickertimer := time.NewTimer(10 * time.Second)<-timer.Cticker.Stop()fmt.Println("timer expired!")}
5. 利用os/exec中的Cmd執行命令
package mainimport ("bytes""fmt""log""os/exec""strings")func main() {cmd := exec.Command("tr", "a-z", "A-Z")cmd.Stdin = strings.NewReader("some input")var out bytes.Buffercmd.Stdout = &outerr := cmd.Run()if err != nil {log.Fatal(err)}fmt.Printf("in all caps: %q\n", out.String())}
6. golang命令列參數解析
package mainimport ("bytes""fmt""log""os/exec""strings")func main() {cmd := exec.Command("tr", "a-z", "A-Z")cmd.Stdin = strings.NewReader("some input")var out bytes.Buffercmd.Stdout = &outerr := cmd.Run()if err != nil {log.Fatal(err)}fmt.Printf("in all caps: %q\n", out.String())}
這樣執行:
#如果沒有指定參數名,則使用預設值$ go run flagtest.gohost: coolshell.cnport: 80debug: false#指定了參數名後的情況$ go run flagtest.go -host=localhost -port=22 -dhost: localhostport: 22debug: true#用法出錯了(如:使用了不支援的參數,參數沒有=)$ go build flagtest.go$ ./flagtest -debug -host localhost -port=22flag provided but not defined: -debugUsage of flagtest:-d=false: enable/disable debug mode-host="coolshell.cn": a host name-port=80: a port numberexit status 2
7. 使用append要注意的問題
1. 先看段簡單的代碼。
a := []int{1, 2, 3, 4, 5}
b = append(a[1:3], 8, 9)
這時fmt.Println(a)的結果是什嗎?
答案是: a = [1, 2, 3, 8, 9]
原因解答:a[1:3]返回的是一個new slice: b。不過這個b沿用了 a原有的空間。
2. 再看個新的
a := []int{1, 2, 3, 4, 5}
b = append(a[1:3], 8, 9, 10)
這時fmt.Println(a)的結果是什嗎?
答案是: a = [1, 2, 3, 4, 5]
原因解答: 因為這次append的資料超過了a的空間大小。所以系統重新開闢了一段空間給b。所以a的資料就不會修改了。
3. 在來一個
a := make([]int, 0, 6)
a = append(a, 1, 2, 3, 4, 5)
b = append(a[1:3], 8, 9, 10)
這時fmt.Println(a)的結果是什嗎?
答案是:(你大概應該猜到了) 是 a = [1, 2, 3, 8, 9]
原因嗎: 看看上一條解答,就明白了。也就是slice以cap空間為標準,沒有超過cap的空間,不會觸發空間的重新分配。
4. 補充一個
a := make([]int, 0, 6)
b := a[:3] // 這個語句合法嗎?
答案是合法的,雖然len(a) == 0, 不過slice取的是cap(a)。 只不過是b = [0, 0, 0]