go语言的魔幻旅程10-协程和信道

397 阅读3分钟

黄沙百战穿金甲,不破楼兰终不还

古代的诗词中,一碰到黄沙、金甲、楼兰这样的字眼的时候总让人不由分说的感受到一种塞外大漠的神秘感,对于绝大部分居住在内陆的人而言,大概这辈子是没有缘分亲眼目睹这一壮观的自然景象,不过非常碰巧的是就在今天的早上还是有辛看到了黄沙漫天的场景,这大概也是人生的初次感受到大自然的力量吧,不过在现代化的今天,论对黄沙的态度,现代人可没有古代人骨子里的浪漫,黄沙虽壮观,放在不同的地点却是一种错误。

go协程

要对go语言的协程有一个全局的概念,首先必须清楚一下的几个基本的概念。

1、什么是并发?什么是并行?并发与并行的区别?

并发是指处理多个任务的能力;并行是指同时处理多个任务的能力;并发指的是一段时间内的概念,而并行指的是某个时刻的概念。

2、什么是进程、什么是线程、什么是协程?

进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发。

线程是进程的子单位,是cpu调度和分配的基本单位,用于保证程序的实时性,实现进程内部的并发,线程是操作系统调度可识别的最小执行可调度单位。

协程是与其他函数或方法一起并发运行的函数或方法,go协程可以看作是轻量级的线程,但与线程相比,创建一个go的协程的成本很小。

3、协程的启动

//举个栗子
func hello() {
    fmt.Println("Hello world goroutine")
}
func main() {
    go hello()
    time.Sleep(1 * time.Second)
    fmt.Println("main function")
}

//多个协程的启动
func numbers() {  
    for i := 1; i <= 5; i++ {
        time.Sleep(250 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}
func alphabets() {  
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(400 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}
func main() {  
    go numbers()
    go alphabets()
    time.Sleep(3000 * time.Millisecond)
    fmt.Println("main terminated")
}

信道channel

1、什么是信道?

信道可以想象成go协程之间通信的管道,如同管道中的水会从一端流向另一端,通过信道,数据可以从一端发送,在另一端接收

2、信道的声明?

信道都关联了一种类型,信道也只能运输这种类型的数据,而运输其他的数据都是非法的。

//举个例子

func main() {  
    var a chan int
    if a == nil {
        fmt.Println("channel a is nil, going to define it")
        a = make(chan int)
        fmt.Printf("Type of a is %T", a)
    }
}

//信道常用的声明方法
a := make(chan int)

3、信道中数据的接收和发送

//信道中数据的读取
data := <- a 

//信道中数据的写入
a <- data

//举个例子
func hello(done chan bool) {  
    fmt.Println("Hello world goroutine")
    done <- true
}
func main() {  
    done := make(chan bool)
    go hello(done)
    <-done
    fmt.Println("main function")
}

4、单向通道

所谓单向的通道就是指声明的信道限制只能接收数据或者发送数据,两者不能同时允许

//举个例子
func sendData(sendch chan<- int) {  
    sendch <- 10
}

func main() {  
    sendch := make(chan<- int)
    go sendData(sendch)
    fmt.Println(<-sendch)
}

5、信道的遍历

//举个栗子
func producer(chnl chan int) {  
    for i := 0; i < 10; i++ {
        chnl <- i
    }
    close(chnl)
}
func main() {  
    ch := make(chan int)
    go producer(ch)
    for v := range ch {
        fmt.Println("Received ",v)
    }
}

6、信道的关闭验证

//检验方式
v, ok := <-ch
if !ok {
  break
}

小结

协程这个部分的内容重点需要掌握的是协程结合信道的相关使用,这两个部分的知识可以说是go这门语言的核心,相比其他的语言,go的协程和信道的有机结合简直可以用某手机大佬发布会的口头禅来形容:“碉堡了”,这个部分的内容也是必须要掌握的。