Go高效并发的关键 | 青训营笔记

101 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

首先,很荣幸能够参加本次青训营,相信这一定是一段美好且收获丰富的旅程啦!

王克纯老师在课程中主要讲解了

  1. Go语言的优势
  2. Go语言的基础语法

本文就学习了王克纯老师的第一堂课,记录下个人的探索和思考。

一、内容概述

本文就不对课程内容进行总结,而是在学习王克纯老师教授内容后,根据网络上的资料、自己的理解(欢迎大家交流、纠正)介绍了: Go高效并发的关键

二、知识点介绍

1. 基本概念

首先,介绍一下几个基础概念,网络中太多这种八股式的介绍,我就不写过多内容,我就用我觉得最通俗易懂的解释来介绍概念(例子c++):

① 进程/线程:./main 将一个main这样的可执行程序运行起来就是一个进程;main.cpp中可以通过pthread调用另起线程。一个进程中的多个线程之间可以并发执行。

② 并发/并行:多线程在单核cpu上运行,主要通过时间片实现并发;多线程程序在多核cpu上运行就是并行。

③ 协程:协程是用户态的线程,跟内核线程是多对一的关系。 image.png

④ 管道:Unix中管道实际上就是一个传输数据的内核缓冲区/文件,其是大小受限的无格式字节流。

2. 高效关键(个人理解)

2.1 goroutine

goroutine其实就是更小的线程,多个goroutine实际上在底层就对应一个线程,它是实现Go语言并发设计的核心。

使用go关键字就可以创建goroutine,调用的函数执行时会被作为一个独立的并发线程。

go DoSomething();

go func(){
    
}(val1, val2)

go {

}

goroutine使得cpu并行运行,那么还有一点疑惑?怎么拿到并行的结果呢? 答案是 通过channel

2.2 channel

channel是Go语言中提供的goroutine间的通信方式,可以在多个goroutine之间传递消息。

go语言提倡使用通信的方式代替共享内存(区别于Unix中共享内存的方式,进程间采用虚拟内存映射到相同的物理内存中,然后就可以实现通信)

1-1PQG035203K.jpg channel是进程内类型相关的通信方式,实际上就是安全的管道,因此定义一个channel需要指明类型,同时通过channel传递对象的过程和调用函数时的参数必须一致。

channel_int := make(chan int)
channel_string := make(chan string)
channel_interface := make(chan interface{})

eg1:
channel_int <- 10
num := <- channel_int

}

数据接收的方式有四种:阻塞接收、非阻塞接收、忽略接收、循环接收 ① 阻塞接收

data := <- ch

② 非阻塞接收

data, ok := <- ch

③ 接收任意数据,并忽略: 执行该语句会阻塞,直到接收到数据。因此可以通过这个方式实现并发


func main() {

    ch := make(chan int)
    
    //开启goroutine匿名函数
    go func() {
        fmt.Println("start goroutine")
        ch <- 0
        fmt.Println("end goroutine")
    }
    
    fmt.Println("wait goroutine")
    <- ch //等待匿名的goroutine
    
    fmt.Println("all done")

④ 循环接收

    for data := range ch {
    
    }

三、个人总结

在学习了王克纯老师的第一堂课后,掌握了go基本语法,并且对于goroutine、channel做了更加深入、细致的学习。

Go语言保证了既能到达静态编译语言的安全和性能,又达到了动态语言开发速度和易维护性。让人联想到C、Python,Go语言结合了C静态语言程序的运行速度 和 Python动态语言的快速开发。

因此,个人觉得:Go语言的高效高并发十分适合于网络IO密集型的场景,诸如服务器开发、网络编程、数据库和云平台领域。