Go中的Channel通讯

runtime包介绍

(图片来自Go语言中文网)
图片来自GO语言中文网

一些较为重要的函数介绍
func NumCPU() int

 
 
  • 1

使用NumCPU方法能够获得一个本地机器的逻辑CPU个数的int类型数值

func GOMAXPROCS(n int)  int

 
 
  • 1

GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。 若 n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过 NumCPU 查询。本函数在调度程序优化后会去掉。
一般来说,在go1.8版本之后,系统会默认使用全部逻辑CPU进行并行操作。而在go1.8之前的版本,则需要自己设置(即使用GOMAXPROCS)。有的时候设计者需要保留一些CPU的功能占用,也会自主设定GOMAXPROCS比最大可用CPU数量少一些。
拓展完毕。接下来进入正题


那么不同的Goroutine之间如何通讯呢?有两种方式:
1、全局变量互斥锁
2、管道Channel

在Go语言中倡导:“不要以共享内存的方式来通信,相反,要通过通信来共享内存。”
首先看一下传统的并发形式:

多线程共享内存,这也是Java、C#或者C++等语言中的多线程开发的常规方法,其实golang语言也支持这种传统模式。

另外一种是Go语言特有的:CSP(Communicating Sequential Processes)并发模型。不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。

在讲同步通信之前先来看一下最简单基础的锁机制

锁机制

锁甚至可以直接理解为同步(Synchronization)。首先了解一下为什么会需要锁机制。在读取和写入这两种方法中,读取是不需要锁的,因为可以多个线程同时读取。而写就不可以,需要加入锁(像最简单的互斥锁Mutex),防止其他的线程进行干扰。
一般情况有两种锁,一种是互斥锁, 一种是读写锁,其中加了互斥锁的程序性能比读写锁的性能要低200倍
(图片来自Go语言中文网)
在这里插入图片描述
举个关于互斥锁的?:有一个电影,多个人同时去看,不会出现问题(读取的线程)。但是拍电影的时候,一个场景只能由一个摄像机去拍摄(纯3D立体除外。。。),不能多个同时拍一个画面,剪切出来的也是一个摄像机拍出来的(写入的线程)。
再举一个关于读写锁的?:在大学课堂都经历过,教室里面有黑板,全班的同学都可以看黑板上面老师的板书(读), 但是能够写黑板的只有老师一个人(写)。那么如果有两个老师同时想要写黑板的话,就会造成同学们无法确定该看(读)谁写的文字。因此其中一个老师在黑板上书写文字内容的时候, 需要把这一过程上锁,一旦上了读写锁,那么第二个老师只能等待第一个老师书写完毕才可以进行书写。

锁主要是为了防止线程之间对于资源的干扰,当一个线程对本身的操作加锁之后(Lock),那么别的线程就无法访问与其相关的内容,这样不会出现干扰,像写入异常等。最经典的就是Data race,资源争夺。
锁需要引入“sync”标准包
(图片来自Go语言中文网)
在这里插入图片描述
由图片对于sync标准包的介绍可以看到,锁一般适用于低水平程序线程,高水平同步应该使用channel通信更好。接下来进入Go的一大特色,channel管道。


管道Channel

先说一下为什么会需要channel。在前面说可以使用加锁来同步解决goroutine的通信,但是并不完美。因为主线程如果退出的话会导致未完成工作的goroutine协程提前退出,这样会出现各种各样的问题。
在我最开始的时候想到通过sleep来获取更多时间,使协程能够运行完毕。但是如果需要运算的内容特别庞大,那么时间就不好把控。sleep时间多了会加长等待切浪费资源,少了,主线程退出goroutine退出销毁程序异常。
而且还存在一个问题,比较不容易判断出在哪里需要增加锁(lock),哪里需要解除锁(unlock)。因此,go设计了一个新的通讯机制Channel。

下面基本介绍一下channel
1、 channel的本质就是一个数据结构-队列
2、channel遵循队列的读取顺序,先进先出(FIFO:first in first out)。
3、channel的线程是很安全的!它是由编译器在底层维护的。多个goroutine对同一个channel进行操作,都可以稳定安全的运行,不出现资源竞争问题。channel本身是不需要使用锁的,但是从源码可以看出,channel本身是有锁,使它本身的机制而来(底层代码实现),我们调用的时候并不需要再去添加或解除锁。
4、channel本身是有数据类型的。string类型的channel只能存放string类型的数据。一般我们都设置为interface{}类型,这样取的时候可以不用进行类型断言去取,免除了一些不必要的麻烦。


未完待续…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言channel、sync.WaitGroup和context是三个非常重要的并发编程工具。下面我将对它们进行详细介绍。 ### Channel Go语言channel是一种在多个goroutine之间进行通信的机制。也可以说,channel是一种数据结构,它可以让一个goroutine向另一个goroutine发送一个值,同时还可以让另一个goroutine从channel接收这个值。在Go语言,使用make函数创建一个channel。例如: ```go ch := make(chan int) ``` 这行代码创建了一个类型为int的channel。可以在goroutine使用ch <- value语句向channel发送一个整数,例如: ```go go func() { ch <- 1 }() ``` 可以使用value := <- ch语句从channel接收一个整数,例如: ```go value := <- ch ``` 这行代码会阻塞,直到有一个整数被发送到这个channel为止。需要注意的是,如果没有接收者,发送操作会一直阻塞,直到有接收者为止;如果没有发送者,接收操作也会一直阻塞,直到有发送者为止。 ### sync.WaitGroup sync.WaitGroup是Go语言的一个同步工具,它可以等待一组goroutine完成工作。在WaitGroup,每个goroutine的工作完成后,都需要调用Done方法。主goroutine可以在Wait方法上阻塞,等待所有的goroutine完成工作。例如: ```go var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { // do some work wg.Done() }() } wg.Wait() ``` 这行代码创建了一个WaitGroup,并且启动了10个goroutine进行工作。每个goroutine完成工作后,都会调用wg.Done方法,主goroutine在wg.Wait上阻塞,等待所有的goroutine完成工作。 ### context context是Go语言的一个用于传递请求范围数据的机制。在一个请求处理,可以使用context携带一些请求数据,同时也可以使用context取消请求处理。例如: ```go func handleRequest(ctx context.Context) { // do some work select { case <-ctx.Done(): // handle cancelation default: // continue working } } ``` 这行代码定义了一个处理请求的函数,该函数接收一个context参数。如果context被取消,处理请求的函数将会停止工作。例如: ```go ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(time.Second) cancel() }() handleRequest(ctx) ``` 这行代码创建了一个带有取消功能的context,并且启动了一个goroutine在1秒后取消context。handleRequest函数会使用这个context来处理请求,并且如果context被取消,handleRequest函数会立刻停止工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值