1. golang程序运行时间显示
package main import ( "fmt" "time" "math/rand" ) func main(){ rand.Seed(time.Now().Unix()) var name string for 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 +0800 go_01 start at 2013-12-05 17:22:34.5367151 +0800 +0800 go_02 start at 2013-12-05 17:22:34.5367151 +0800 +0800 go_02 end at 2013-12-05 17:22:36.5548305 +0800 +0800 go_02 lasted 2.0181154s go_00 end at 2013-12-05 17:22:37.5558878 +0800 +0800 go_00 lasted 3.0221729s go_01 end at 2013-12-05 17:22:38.5549449 +0800 +0800 go_01 lasted 4.0182298s j Done
2. 利用mutex控制goroutine的执行
package main import "fmt" import "time" import "math/rand" import "sync" import "runtime" //var total_tickets int32 = 10 var mutex = &sync.Mutex{} //可简写成:var mutex sync.Mutex func sell_tickets(i int, t time.Duration) { var total_tickets int32 = 10 for { 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核处理器,所以我设置了4 rand.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 string fmt.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 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)
default: //default会导致无阻塞
fmt.Println("nothing received!")
time.Sleep(time.Second)
//break永远也不会执行
break
}
}
}
关闭channel,总是在发送端关闭:
package main import "fmt" import "time" import "math/rand" func main() { channel := make(chan string) rand.Seed(time.Now().Unix()) //向channel发送随机个数的message go 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 = true var msg string for more { select{ //channel会返回两个值,一个是内容,一个是bool case msg, more = <- channel: if more { fmt.Println(msg) }else{ fmt.Println("channel closed!") } } } }
4. golang的定时器
Go语言中可以使用time.NewTimer或time.NewTicker来设置一个定时器,这个定时器会绑定在你的当前channel中,通过channel的阻塞通知机器来通知你的程序。
package main import "time" import "fmt" func main() { ticker := time.NewTicker(time.Second) go func() { for t := range ticker.C { fmt.Println(t) } }() //设置一个timer,10钞后停掉ticker timer := time.NewTimer(10 * time.Second) <-timer.C ticker.Stop() fmt.Println("timer expired!") }
5. 利用os/exec中的Cmd执行命令
package main import ( "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.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { log.Fatal(err) } fmt.Printf("in all caps: %q\n", out.String()) }
6. golang命令行参数解析
package main import ( "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.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { log.Fatal(err) } fmt.Printf("in all caps: %q\n", out.String()) }
这样执行:
#如果没有指定参数名,则使用默认值 $ go run flagtest.go host: coolshell.cn port: 80 debug: false #指定了参数名后的情况 $ go run flagtest.go -host=localhost -port=22 -d host: localhost port: 22 debug: true #用法出错了(如:使用了不支持的参数,参数没有=) $ go build flagtest.go $ ./flagtest -debug -host localhost -port=22 flag provided but not defined: -debug Usage of flagtest: -d=false: enable/disable debug mode -host="coolshell.cn": a host name -port=80: a port number exit 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]