Go语言进阶及依赖管理|青训营笔记

47 阅读2分钟

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

go的并发编程

在操作系统中,进程是资源分配的基本单位,线程是系统调度的基本单位,它们共享同个进程中的资源;除此之外进程中还有协程,也称为轻量级线程,其最大的优势是“轻量级”,可以轻松创建上百万个协程而不会导致系统资源衰竭,而线程和进程通常最多也不能超过1万个。

而在go语言中,在语言级别支持协程,叫goroutine。

goroutine是通过Go程序的runtime管理的一个线程管理器。goroutine通过go关键字实现了,其实就是一个普通的函数。

下面通过一个简单示例演示一下:

package main

import (
   "fmt"
   "time"
)

func say(str string) {
   for i := 0; i < 4; i++ {
      fmt.Println(str)
   }
}

func main() {
   go say("Hello")
   fmt.Println("world")
   time.Sleep(time.Second)
}

此处需要等待go所在的语句执行完才能推出main,因为main的协程会比他更快退出,因此在main中创建的协程也会退出

输出结果:

world

Hello

Hello

Hello

Hello

go的通道

虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,但是这么做又会影响到性能

Go语言提倡通过通信共享内存而不是通过共享内存而实现通信。

如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。

Go 语言中的通道(channel)是一种特殊的类型。通道像一个队列,遵循先入先出的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。

package main

import (
   "fmt"
)

func recv(c chan int) {
   ret := <-c
   fmt.Println("成功接收", ret)
}
func main() {
   ch := make(chan int)
   fmt.Println("开始发送")
   go recv(ch) // 启用goroutine从通道接收值
   ch <- 10
   fmt.Println("发送成功")
}

上面这个示例就是一个没有缓冲的通道的示例,当然channel初始化的时候是可以指定长度的,也就成了有缓冲的通道

package main

import (
   "fmt"
)


func recv(c chan int) {
   ret := <-c
   fmt.Println("成功接收", ret)
}
func main() {
   ch := make(chan int, 1)
   fmt.Println("开始发送")
   go recv(ch) // 启用goroutine从通道接收值
   ch <- 10
   ch <- 20
   fmt.Println("发送成功")
   fmt.Print("通道剩余元素数:")
   fmt.Println(len(ch))
}

个人感想

通过对进阶课程的学习,对go语言是面对并发的语言这句话有了更深的了解,同时对go语言的并发编程有了初步的了解,对于通道的使用也有了一定的了解