[go]并发编程,go关键字和select关键字

其实和if switch for等循环结构一样. go 是一种控制结构, 控制协程的启动等生命周期.

并发基础

程序与进程

并发与并行

启动多个协程

// 同步代码
func hello() {
    time.Sleep(time.Second/3)
        fmt.Println("Hello Goroutine!")
}
func main() {
        hello()
        fmt.Println("main goroutine done!")
}
//异步
func hello() {
    time.Sleep(time.Second/3)
        fmt.Println("Hello Goroutine!")
}
func main() {
        go hello()                          // 启动另外一个goroutine去执行hello函数
        fmt.Println("main goroutine done!") //不会被输出
}

//main结束,程序即运行结束
func main() {
        go hello() // 启动另外一个goroutine去执行hello函数
        fmt.Println("main goroutine done!")
    time.Sleep(time.Second)
}
  • 协程同步
- runtime包里的函数

// runtime.GOMAXPROCS() 设置核心数

- 用一个core执行
func main() {
        runtime.GOMAXPROCS(1)
        go func() {
                for {
                        fmt.Print(1)

                }
        }()
        go func() {
                for {
                        fmt.Print(2)
                }
        }()
        time.Sleep(time.Second * 1)
}
//打印的1 2 成块的


- 用2个core执行
func main() {
        runtime.GOMAXPROCS(2)
        go func() {
                for {
                        fmt.Print(1)

                }
        }()
        go func() {
                for {
                        fmt.Print(2)
                }
        }()
        time.Sleep(time.Second * 1)
}
//打印的1 2交替较明显
// runtime.Gosched() //出让当前执行机会, 等下次又机会时继续往下执行
func main() {
        runtime.GOMAXPROCS(1)
        go func() {
                for {
                        fmt.Print("m")

                }
        }()
        go func() {
                for {
                    runtime.Gosched()
                        fmt.Print("g")
                }
        }()
        time.Sleep(time.Second)
}
- runtime.Goexit()结束本go程
- return结束当前函数
// return结束当前函数
func test() {
        println(1)
        return
        println(2)
}

func main() {
        test()
        println("main")
}
//1
//main
//runtime.Goexit结束当前go程
func test() {
        println(1)
        runtime.Goexit()
        println(2)
}

func main() {
        test()
        println("main")
}
// 1
// fatal error: no goroutines (main called runtime.Goexit) - deadlock!
// defer: 当函数结束时被调用

func main() {
        defer println("test end 1") //栈结构:一个桶 后进先出
        defer println("test end 2")
        println("testing")
}
//testing
//test end 2
//test end 1
// return后的defer不会被注册
func main() {
        defer println("1")
        println("main")
        return
        defer println("2")
}
//main
//1
// runtime.Goexit后的defer不会被注册
func main() {
        defer println("1")
        println("main")
        runtime.Goexit()
        defer println("2")
}
//main
//1
//fatal error: no goroutines (main called runtime.Goexit) - deadlock!
- 小结: 
    runtime.Goexit()和return后的defer都不会被注册, 
    只有代码能执行到,defer才会被注册

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        runtime.Goexit()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second * 1)
}
//aaaaaaaaaaaaa


func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        return
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second * 1)
}
//aaaaaaaaaaaaa
// 带go
func test() {
    defer fmt.Println("ccccccccccc")
    runtime.Goexit()
    defer fmt.Println("dddddddddddddd")
}

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        go test()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second)
}
//bbbbbbbbbb
//aaaaaaaaaaaaa
//ccccccccccc
//不带go
func test() {
    defer fmt.Println("ccccccccccc")
    runtime.Goexit()
    defer fmt.Println("dddddddddddddd")
}

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        test()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second)
}
//ccccccccccc
//aaaaaaaaaaaaa

定时器

[go]time包

睡一秒

//方法1:
func main() {
    time.Sleep(time.Second)
}

//方法2:
func main() {
        fmt.Println(<-time.NewTimer(time.Second).C))
}

//方法3:
func main() {
    fmt.Println(<-time.After(time.Second))
}

// 定时回调(setTimeout)
time.AfterFunc(time.Second, func() {
    println("after 1s cb")
})
time.Sleep(time.Second*3)
//周期定时器(setInterval)
func main() {
        tickTimer := time.NewTicker(time.Second)
        for {
                fmt.Println(<-tickTimer.C)
        }
}

select - 管理多个chan

select是一种控制结构, 和if switch for控制结构一样, 用于控制管理多个管道

Go并发编程—select的使用

select可以同时监控多个通道的情况,只处理未阻塞的case。
每个case必须是一个chan的io操作

select会阻塞在多个channel上,对多个channel的读/写事件进行监控。
case中的channel的事件包括:
    读取的时候,
    channel被close,或
    写入时channel没有空间。
// 多个chan,随机选一个执行. 对多个chanel调度机会基本是均等的

当通道为nil时,对应的case永远为阻塞,无论读写。
    特殊关注:普通情况下,对nil的通道写操作是要panic的。
func main() {
    c1 := make(chan interface{}); close(c1)
    c2 := make(chan interface{}); close(c2)
    c3 := make(chan interface{}); close(c3)

    var c1Count, c2Count, c3Count int
    for i := 1000; i >= 0; i-- {
        select {
        case <-c1:
            c1Count++
        case <-c2:
            c2Count++
        case <-c3:
            c3Count++
        }
    }
    fmt.Printf("c1Count: %d\nc2Count: %d\nc3Count: %d\n", c1Count, c2Count, c3Count)
}
//select管理多个管道
func main() {
        ch := make(chan int, 1) //仅限于缓冲通道
        for i := 0; i < 10; i++ {
                select {
                case x := <-ch:
                        fmt.Println(x)
                case ch <- i:
                }
        }
}
// select管理多个管道
func main() {
        ch := make(chan int)
        done := make(chan bool)
        go func() {
                for i := 0; i < 10; i++ {
                        ch <- i
                        time.Sleep(time.Second / 3)
                }
                close(ch)
                done <- true
        }()
        for {
                select {
                case <-done:
                        fmt.Println("Done!")
                        return
                case t := <-ch:
                        fmt.Println("ch value: ", t)
                }
        }
}

// 没有任何channel准备好,处理默认事件
func main() {
        start := time.Now()
        var c1, c2 <-chan int
        select {
        case <-c1:
        case <-c2:

        default:
                fmt.Printf("In default after %v\n\n", time.Since(start))
        }
}

// 没有任何channel准备好,处理超时

func main() {
    var c <-chan int

    for {
        select {
        case <-c:
        case <-time.After(1 * time.Second):
            fmt.Println("Timed out.Do something.")
        }
    }
}
2. 退出

select {
    case <- done:
        cleanUp()
        return
    default:
}
3.判断channel是否阻塞
func main() {
        var ch chan int = make(chan int, 5)
        for {
                select {
                case ch <- 1:
                        fmt.Println("add success")
                default: // channel满了
                        fmt.Println("chan is full")
            return
                }
        }
}
4.检测chanel关闭事件
func main() {
    start := time.Now()
    c := make(chan interface{})

    go func() {
        time.Sleep(2*time.Second)
        close(c)
    }()

    fmt.Println("Blocking on read...")
    select {
    case <-c:
        fmt.Printf("Unblocked %v later.\n", time.Since(start))
    }
}

// select{} 永久阻塞, 直到有信号中断.
func main() {
        go func() {
                for {
                        fmt.Println(time.Now())
                        time.Sleep(time.Second / 3)
                }
        }()

        select {}
}