通道同步

func worker(done chan bool) {    fmt.Println("working...")    time.Sleep(2 * time.Second)    fmt.Println("done")    done <- true}func main() {    done := make(chan bool, 1)    go worker(done)    <-done}

后果:

working...done[Finished in 3.1s]

通道抉择

import (    "fmt"    "time")func main() {    ch1 := make(chan string, 1)    ch2 := make(chan string, 2)    go func() {        time.Sleep(time.Second * 2)        ch1 <- "one"    }()    go func() {        time.Sleep(time.Second)        ch2 <- "two"    }()    select {    case msg1 := <-ch1:        fmt.Println(msg1)    case msg2 := <-ch2:        fmt.Println(msg2)    }}

后果:

$ go run  main.gotwo

超时解决

func main() {    ch1 := make(chan string, 1)    go func() {        time.Sleep(time.Second * 1)        ch1 <- "1"    }()    select {    case res := <-ch1:        fmt.Println(res)    case <-time.After(time.Second * 1):        fmt.Println("time out 1")    }    ch2 := make(chan string, 1)    go func() {        time.Sleep(time.Second * 2)        ch2 <- "2"    }()    select {    case res := <-ch1:        fmt.Println(res)    case <-time.After(time.Second * 1):        fmt.Println("time out 2")    }}

后果:

$ go run  main.go1time out 1

非阻塞通道

func main() {    message := make(chan string)    select {    case msg := <-message:        fmt.Print("message", msg)    default:        fmt.Println("no message receive")    }    msg := "1"    select {    case message <- msg: // 当message通道定义一个缓冲区的时候,这里能够执行        fmt.Println("sent message")    default:        fmt.Println("no message sent")    }}

后果

$ go run  main.gono message receiveno message sent

通道敞开

func main() {    jobs := make(chan int, 5)    done := make(chan bool)    go func() {        for {            j, ok := <-jobs            if ok {                fmt.Println("receive job ", j)            } else {                fmt.Println("receive all jobs")                done <- true      // 告诉主程序,曾经承受全副工作                return            }        }    }()    for i := 1; i < 3; i++ {        jobs <- i        fmt.Println("send job", i)    }    close(jobs)    fmt.Println("send all jobs")    <-done  //期待告诉}

后果

$ go run main.gosend job 1send job 2send all jobsreceive job  1receive job  2receive all jobs

遍历通道

func main() {    queue := make(chan string, 3)    queue <- "one"    queue <- "two"    close(queue)    for elem := range queue {        fmt.Println(elem)    }}

后果:

$ go run main.goonetwo

定时器

func main() {    timer1 := time.NewTimer(time.Second * 2)    <-timer1.C    fmt.Println("timer 1 expired")    timer2 := time.NewTimer(time.Second * 2)    <-timer2.C    fmt.Println("timer 2 expired")    stop2 := timer2.Stop() // 此时timer2曾经倒计时完结了,所以不须要进行    fmt.Println("stop2:", stop2)    if stop2 {        fmt.Println("timer 2 stoped")    }}

后果:

$ go run main.gotimer 1 expiredtimer 2 expiredstop2: false

下面例子中,因为timer2的倒计时曾经进行,timer2.stop()没有执行,返回为false,如果想看进行成果,能够改写代码:

func main() {    timer1 := time.NewTimer(time.Second * 2)    <-timer1.C    fmt.Println("timer 1 expired")    timer2 := time.NewTimer(time.Second * 5)    go func() {        <-timer2.C        fmt.Println("timer 2 expired")    }()    stop2 := timer2.Stop()     fmt.Println("stop2:", stop2)    if stop2 {        fmt.Println("timer 2 stoped")    }}

后果:

$ go run main.gotimer 1 expiredstop2: truetimer 2 stoped

能够看到stop2进行了计时器,程序间接退出了。

也能够应用time自带的after办法实现

func main() {    ch := make(chan string)    go func() {        time.Sleep(time.Second * 2)        ch <- "result"    }()    select {    case res := <-ch:        fmt.Println(res)    case <-time.After(time.Second * 1):        fmt.Println("timeout")    }}

后果:

$ go run main.gotimeout

计时器

Ticker和timer的区别是,timer倒计时到某一个工夫点发送一个信号,而ticker是每隔多长时间发送一个信息,直到咱们手动stop

func main() {    ticker := time.NewTicker(time.Second)    go func() {        for t := range ticker.C {            fmt.Println("Tick at ", t)        }    }()    time.Sleep(time.Second * 5)    ticker.Stop()    fmt.Println("ticker stopped")}

后果:

$ go run main.goTick at  2021-05-20 08:55:17.817703 +0800 CST m=+1.003478727Tick at  2021-05-20 08:55:18.819047 +0800 CST m=+2.004844288Tick at  2021-05-20 08:55:19.814649 +0800 CST m=+3.000467753Tick at  2021-05-20 08:55:20.81894 +0800 CST m=+4.004780216ticker stoppedTick at  2021-05-20 08:55:21.815348 +0800 CST m=+5.001210115

后果是每隔1秒将以后工夫作为值push到通道,而后咱们循环这个通道获取值。通过源码能够看到Ticker.C是一个time类型的channel。

源码:

type Ticker struct {    C <-chan Time // The channel on which the ticks are delivered.    r runtimeTimer}

工作池

func worker(id int, jobs <-chan int, results chan<- int) {    for j := range jobs {        fmt.Println("worker", id, "process job", j)        time.Sleep(time.Second * 2)        results <- j     }}func main() {    jobs := make(chan int, 100)    results := make(chan int, 100)    // 开启5个过程    for w := 1; w <= 5; w++ {        go worker(w, jobs, results)    }    // 向通道push工作    for j := 1; j <= 9; j++ {        jobs <- j    }        close(jobs)        for r := 1; r <= 9; r++ {        <-results    }}

result作用是告知主过程执行完结,当所有的执行完结后,主过程完结退出工作,如果没有result可能会导致子过程还没有完结,主过程就退出了。
后果

worker 3 process id 1worker 1 process id 2worker 2 process id 3worker 1 process id 4worker 2 process id 6worker 3 process id 5worker 2 process id 8worker 1 process id 9worker 3 process id 7

限速

func main() {    // 限度每2秒执行一次申请    ticker := time.Tick(time.Second * 2)    for i := 1; i <= 5; i++ {        <-ticker        fmt.Println("request", i, time.Now())    }    // 先向burstylimiter push 3个值    limiter := make(chan time.Time, 3)    for i := 0; i < 3; i++ {        limiter <- time.Now()    }    // 而后开启另外一个线程,每2秒向burstylimiter push 一个值    go func() {        for t := range time.Tick(time.Second * 2) {            limiter <- t        }    }()    // 最初实现成果,前三次没有限速,最初两次每2秒执行一次    for i := 1; i <= 5; i++ {        <-limiter        fmt.Println("request", i, time.Now())    }}

后果:

request 1 2021-05-20 10:09:01.121992 +0800 CST m=+2.005258478request 2 2021-05-20 10:09:03.117609 +0800 CST m=+4.000918022request 3 2021-05-20 10:09:05.116884 +0800 CST m=+6.000235109request 4 2021-05-20 10:09:07.11969 +0800 CST m=+8.003084206request 5 2021-05-20 10:09:09.119841 +0800 CST m=+10.003278026request 1 2021-05-20 10:09:09.119978 +0800 CST m=+10.003414895request 2 2021-05-20 10:09:09.120101 +0800 CST m=+10.003538622request 3 2021-05-20 10:09:09.12018 +0800 CST m=+10.003616297request 4 2021-05-20 10:12:29.322124 +0800 CST m=+12.005434486request 5 2021-05-20 10:12:31.322453 +0800 CST m=+14.005806367

成果:前5次,距离2s,第6-8次,不间隔时间,9-10次再次距离2s执行。

互斥锁

func main() {    var state = make(map[int]int)    var mutex = &sync.Mutex{}    for w := 0; w < 10; w++ {        go func() {            for {                key := rand.Intn(5)                val := rand.Intn(100)                mutex.Lock()           // 加锁                state[key] = val                mutex.Unlock()         // 解锁            }        }()    }    time.Sleep(time.Second)    fmt.Println("state:", state)}

后果:

$ go run main.gostate: map[0:72 1:25 2:36 3:44 4:38]

当去掉互斥锁配置当前,代码报错,因为同时读写一块内存地址。

go状态协程

func main() {    reads := make(chan *readOp)    writes := make(chan *writeOp)    // 通过select抉择来保障同时只能读或写操作    go func() {        var state = make(map[int]int)        for {            select {            case read := <-reads:                read.resp <- state[read.key]            case writes := <-writes:                state[writes.key] = writes.val                writes.resp <- true            }        }    }()    for r := 0; r < 100; r++ {        go func() {            for true {                read := &readOp{                    key:  rand.Intn(5),                    resp: make(chan int),                }                reads <- read            }        }()    }    for w := 0; w < 10; w++ {        go func() {            for {                write := &writeOp{                    key:  rand.Intn(5),                    val:  rand.Intn(100),                    resp: make(chan bool),                }                writes <- write                <-write.resp            }        }()    }    time.Sleep(time.Second)}

这里通过select抉择来保障同时只有一个读或写操作,这样比通过互斥锁简单。

排序

func main() {    strs := []string{"c", "a", "b"}    sort.Strings(strs)    fmt.Println("Strings:", strs)    ints := []int{1, 6, 3, 5, 2}    sort.Ints(ints)    fmt.Println("Ints:", ints)    // 判断是否排序    s := sort.IntsAreSorted(ints)    fmt.Println("Sorted:", s)}

自定义规定排序

以字符串长度排序

type ByLength []stringfunc (b ByLength) Len() int {    return len(b)}func (b ByLength) Swap(i, j int) {    b[i], b[j] = b[j], b[i]}func (b ByLength) Less(i, j int) bool {    return len(b[i]) < len(b[j])}func main() {    fruits := []string{"apple", "banana", "kiwi", "orage"}    sort.Sort(ByLength(fruits))    fmt.Println(fruits)}

后果

$ go run main.go[kiwi apple orage banana]

正则表达式

func main() {    match, _ := regexp.MatchString("p([a-z]+)ch", "peach")    fmt.Println(match)    r, _ := regexp.Compile("p([a-z]+)ch")    fmt.Println(r.MatchString("peach"))    fmt.Println(r.Match([]byte("peach")))    fmt.Println(r.FindString("peach punch"))    fmt.Println(r.FindStringIndex("peach punch"))    fmt.Println(r.FindStringSubmatch("peach punch"))    fmt.Println(r.FindStringSubmatchIndex("peach punch"))    fmt.Println(r.FindAllString("peach punch pinch", -1))    fmt.Println(r.FindAllString("peach punch pinch", 2))    fmt.Println(r.FindAllString("peach punch pinch", 1))    fmt.Println(r.FindAllStringSubmatch("peach pinch punch", -1))    fmt.Println(r.FindAllStringSubmatchIndex("peach pinch punch", -1))    r = regexp.MustCompile("p([a-z]+)ch")    fmt.Println(r)    fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))    in := []byte("a peach")    out := r.ReplaceAllFunc(in, bytes.ToUpper)    fmt.Println(string(out))}

后果:

truetruetruepeach[0 5][peach ea][0 5 1 3][peach punch pinch][peach punch][peach][[peach ea] [pinch in] [punch un]][[0 5 1 3] [6 11 7 9] [12 17 13 15]]p([a-z]+)cha <fruit>a PEACH

工夫戳

func main() {    now := time.Now()    secs := now.Unix()    nanos := now.UnixNano()    fmt.Println(now)    fmt.Println(secs)    fmt.Println(nanos)    fmt.Println(time.Unix(secs, 0))    fmt.Println(time.Unix(0, nanos))}

后果:

2021-05-21 09:19:47.347155 +0800 CST m=+0.000135175162155998716215599873471550002021-05-21 09:19:47 +0800 CST2021-05-21 09:19:47.347155 +0800 CST

数字解析

将字符串解析成对应的数字类型,当遇到无奈解析时,会报错。

func main() {    f, _ := strconv.ParseFloat("1.234", 64)    fmt.Println(f)    i, _ := strconv.ParseInt("1234", 0, 64)    fmt.Println(i)    k, _ := strconv.Atoi("135")    fmt.Println(k)    _, e := strconv.Atoi("wat")    fmt.Println(e)}

后果:

1.2341234135strconv.Atoi: parsing "wat": invalid syntax

解析URL地址

func main() {    s := "postgres://user:pass@host.com:5432/path?k=v#f"    u, err := url.Parse(s)    if err != nil {        panic(err)    }    fmt.Println(u.User.Username())    p, _ := u.User.Password()    fmt.Println(p)    fmt.Println(u.Host)    fmt.Println(strings.Split(u.Host, ":")[0])    fmt.Println(strings.Split(u.Host, ":")[1])    // 获取门路    fmt.Println(u.Path)    // 获取参数值    fmt.Println(u.Fragment)    fmt.Println(u.RawQuery)}

后果:

$ go run main.gouserpasshost.com:5432host.com5432/pathfk=v

SHA1散列

func main() {    s := "sha1 shis string"    // 创立一个sha1对象    h := sha1.New()    // 对字符串解决    h.Write([]byte(s))    // sumk能够用来对现有字符串切片追加额定字节,个别不须要    bs := h.Sum(nil)    fmt.Println(s)    fmt.Printf("%x\n", bs)}

后果:

sha1 shis string6bf8cad402882fb0fc2aed041dcc79b8e686cfc6

Scan过滤

func main() {    // 从命令行获取数据    scanner := bufio.NewScanner(os.Stdin)    for scanner.Scan() {        ucl := strings.ToUpper(scanner.Text())        fmt.Println(ucl)    }    if err := scanner.Err(); err != nil {        fmt.Fprintln(os.Stderr, "error", err)        os.Exit(1)    }}

后果:

$ echo "nihaoya" |go run main.goNIHAOYA

命令行参数

func main() {    argsWithProg := os.Args    argsWithoutProg := os.Args[1:]    arg := os.Args[3]    fmt.Println(argsWithProg)    fmt.Println(argsWithoutProg)    fmt.Println(arg)}

后果:

[/var/folders/p0/cv96ln_j6t7d6g_lwfwcqgqc0000gn/T/go-build765472776/b001/exe/main a b c d][a b c d]c

环境变量

func main() {    os.Setenv("FOO", "1")    fmt.Println("FOO:", os.Getenv("FOO"))    fmt.Println("BAR:", os.Getenv("BAR"))    for _, e := range os.Environ() {        pair := strings.Split(e, "=")        fmt.Println(pair[0])    }}

后果:

FOO: 1BAR: __INTELLIJ_COMMAND_HISTFILE__HOME__CF_USER_TEXT_ENCODINGLOGIN_SHELLPATHLC_CTYPEUSERSSH_AUTH_SOCKTMPDIRSHELLLOGNAMEXPC_SERVICE_NAMEGO111MODULEGOPATHXPC_FLAGSGOROOT

执行系统命令

func main() {    // 执行工夫命令    dateCmd := exec.Command("date")    dateOut, err := dateCmd.Output()    if err != nil {        panic(err)    }    fmt.Println(string(dateOut))    // 执行ls命令    lsCmd := exec.Command("bash", "-c", "ls -a -l -h")    lsOut, err := lsCmd.Output()    if err != nil {        panic(err)    }    fmt.Println(string(lsOut))    // 执行grep命令    grepCmd := exec.Command("grep", "hello")    // 获取输出和输入对象    grepIn, _ := grepCmd.StdinPipe()    grepOut, _ := grepCmd.StdoutPipe()    // 开始执行    grepCmd.Start()    // 输出字符    grepIn.Write([]byte("hello grep\ngoodbye grep"))    grepIn.Close()    // 读取输入    grepBytes, _ := ioutil.ReadAll(grepOut)    grepCmd.Wait()    fmt.Println("> grep hello")    fmt.Println(string(grepBytes))}

后果:

$ go run main.goFri May 21 11:33:32 CST 2021total 160drwxr-xr-x  17 liangkai  admin   544B May 21 11:33 .drwxr-xr-x@ 21 liangkai  admin   672B May 17 17:40 ..-rw-r--r--@  1 liangkai  admin    10K May 17 18:48 .DS_Store-rw-r--r--   1 liangkai  admin    67B Dec 21 12:08 .envdrwxr-xr-x   8 liangkai  admin   256B May 19 17:47 .ideadrwxr-xr-x   3 liangkai  admin    96B Apr 30 08:13 .vscodedrwxr-xr-x   4 liangkai  admin   128B Apr 30 15:37 Otherdrwxr-xr-x   4 liangkai  admin   128B Dec 21 09:13 PracChandrwxr-xr-x   4 liangkai  admin   128B Apr 12 16:54 PracCodeSvndrwxr-xr-x   3 liangkai  admin    96B Mar  3 10:59 PracExporterdrwxr-xr-x   7 liangkai  admin   224B Apr 30 15:37 PracHttpdrwxr-xr-x   5 liangkai  admin   160B Dec 21 09:10 PracInterfacedrwxr-xr-x   6 liangkai  admin   192B Apr 30 14:46 base-rw-r--r--   1 liangkai  admin   147B Feb 20 18:44 config.ini-rw-r--r--   1 liangkai  admin   798B Apr 30 15:41 go.mod-rw-r--r--   1 liangkai  admin    52K Apr 30 15:41 go.sum-rw-r--r--@  1 liangkai  admin   725B May 21 11:33 main.go> grep hellohello grep

零碎信号

func main() {    sigs := make(chan os.Signal, 1)    done := make(chan bool, 1)    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)    go func() {        sig := <-sigs        fmt.Println()        fmt.Println(sig)        done <- true    }()    fmt.Println("waitting signal")    <-done    fmt.Println("exiting")}

后果:

$ go run main.gowaitting signal^Cinterruptexiting