golang小程序试验(二)

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]


本文来自:开源中国博客

感谢作者:壬癸甲乙

查看原文:golang小程序试验(二)

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。