1、goroutine

(1)通过go关键字创建一个协程
(2)主协程退出后,子协程也会退出

package main

import (
    "fmt"
    "time"
)

func main() {
    // 新建一个协程
    go newTask()

    // 主协程退出后,子协程也会退出
    i := 0
    for {
        i++
        fmt.Println("main")
        time.Sleep(time.Second)
        if i == 3 {
            break
        }
    }
}

func newTask() {
    for {
        fmt.Println("newTask")
        time.Sleep(time.Second)
    }
}

2、runtime包

(1)n := runtime.GOMAXPROCS(1) -> 指定协程的核心数,返回之前的核心数
(2)runtime.Goexit() -> 终止所在的协程
(3)runtime.Gosched() -> 让出时间片,先让其他协程执行,再回来执行这个协程

package main

import (
    "fmt"
    "runtime"
)

func main() {
    // 指定协程的核心数,返回之前的核心数
    n := runtime.GOMAXPROCS(1)
    fmt.Println("n = ", n)

    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println("goroutine")
            if i == 2 {
                // 终止所在的协程
                runtime.Goexit()
            }
        }
    }()

    for i := 0; i < 3; i++ {
        // 让出时间片,先让其他协程执行,再回来执行这个协程
        runtime.Gosched()
        fmt.Println("mian")
    }
}

3、channel

(1)创建channel,make(chan Type),make(chan Type,capacity)

  • 无缓冲的channel,如果里边的数据不读,写数据会阻塞
  • 有缓冲的channel,当channel满了,写数据也会阻塞

(2)channel <- 向channel中写数据
(3)从channel中读取数据,如果没有数据,将阻塞;

  • <- channel:接受并丢弃数据
  • x := <- channel :从channel中读取数据,赋值给x
  • x,ok := <- channel :从channel中读取数据,并判断channe是否已经关闭或者是否为空
  • for data:= rang channel:通过rang获取管道的数据

(4)close(channel) 关闭channel,无法再发送数据,但是可以读数据
(5)双向channel能隐式转换成单项channel:chan<- 、<-chan

package main

import (
    "fmt"
    "time"
)

var ch = make(chan int)

func main() {
    go func() {
        Printer("hello")
        // 给管道写数据
        ch <- 1
    }()
    go func() {
        // 从管道取数据,如果没有数据就阻塞
        <-ch
        Printer("world")
    }()

    for {

    }
}

func Printer(world string) {
    for _, data := range world {
        fmt.Printf("%c", data)
        time.Sleep(time.Second)
    }
    fmt.Println()
}

4、timer

(1)timer := time.NewTimer(2 * time.Second):实现延时功能
(2)timer.Stop():停止定时器,
(3)timer.Reset(2 * time.Second):重新设置timer的时间

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now())
    // 直接返回一个管道
    timer := time.After(2 * time.Second)

    t := <-timer
    fmt.Println(t)
}

func main1() {
    fmt.Println(time.Now())
    time.Sleep(2 * time.Second)
    fmt.Println(time.Now())
}

func main2() {
    // 创建一个定时器,2s后,往time通道写入当前时间
    timer := time.NewTimer(2 * time.Second)
    fmt.Println(time.Now())

    t := <-timer.C
    fmt.Println(t)
}

5、ticker

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Second)

    i := 0
    for {
        <-ticker.C
        i++
        fmt.Println("", i)
        if i == 5 {
            ticker.Stop()
            break
        }
    }
}

6、select

select 中 case的条件必须是一个io操作

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    quit := make(chan bool)

    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-ch)
        }
        quit <- false
    }()

    feibona(ch, quit)
}

func feibona(ch chan<- int, quit <-chan bool) {
    ticker := time.After(5 * time.Second)
    x, y := 1, 1
    for {
        select {
        case ch <- x:
            x, y = y, x+y
            time.Sleep(time.Second)
        case flag := <-quit:
            if flag {
                fmt.Println("结束啦:", flag)
                return
            } else {
                fmt.Println("收到标记:", flag)
            }
        case <-ticker:
            fmt.Println("超时啦")
            return
        }
    }
}