golang 并发
所有工具的简单介绍
1 goroutine:
准确来说这并不是一个和C#Java一样的线程,而是golang runtime管理的一个轻量级线程,但是我们完全可以把他当做是一个线程,使用go关键字来开启
2 channel:
这是一种通信方式,相当于不同线程之间建立了管道通信的机制,管道有很多种,但是只要把握住核心功能“通信”,就不会感到迷茫,很巧妙的解决了共享内存的线程的诸多问题
3 select:
这相当于是对channel进行集中处理的工具,就像战争片里的指挥所里一群人在一起使用电报进行集中收发,当一个线程需要受到很多信息 或者说管道的影响的时候,必然需要对这些信息进行集中管理
4 sync包:
提供了一些工具,分别有各种锁 mutex,waitGroup,once,atomic……,这几个是主要的,mutex是解决并发运行的时候数据错乱的方式,类似于数据库遇到的各种幻读,脏读等情况,有了锁就能实现一些原子化操作,waitGroup相当于是一个计数器,wg.wait会一直等待,直到wg.Done调用的次数多余wg.Add(n) 的时候才会停止阻塞继续运行,once也和数量有关,一个once只能执行一次操作,atomic是一些已经写好了的原子化操作,比如a=a+1并不是原子化的,但是atomic.AddInt64(&a,1)就是原子化的,context可以理解为一种特殊的管道操作,不过专门负责控制取消线程。
可以看到这个包是对线程的具体内容进行控制
5 time包中的Ticker:
我认为这个也很重要,在一些涉及到时间的并发场景中这个会十分方便,比如轮询之类的操作。
goroutine
完全可以把他当做线程对待,使用go进行调用,一般使用两种姿势
go functionName(arguments)
或者
go func() {
// 函数体
}()
channel
最普通的channel创建:
var ch chan strign
ch=make(chan string)
销毁:
close(ch)
使用:
ch<-msg
msg:=<-ch
//这里有个注意,所有的使用方式都只能是<-向左,不像C++方向可以变<< 或者 >>
不管是发送还是接受信息的时候,这种最简单的管道在没有联系完成的时候会一直堵塞住,简单的来说,如果ch<-"hhha",会一直堵塞到有线程接收了这个hhha不然发送线程就会一直堵塞,同理,在接收线程的msg<-ch语句没有接收到信息的时候,也会一直堵塞住。而这种堵塞会一直持续,一直到什么时候联系完成或者通道关闭,关闭的时候,会直接给msg赋0值,比如string
就会是“”。
这是最基础的channel,为什么设计成这样,这是谷歌多年来无数代码总结的经验,这种方式牺牲了一部分并发的效率,但是出错的概率很小,虽然不够灵活,但是基本的功能其实已经完成了,golang完成异步编程的办法和C#等不一样,go接受了异步代码和同步不一样的事实,选择让开发者使用channel自己控制逻辑,我认为更灵活,并且,在最基础的channel上还加上一些升级功能,如下。
升级一:
双值接受,当通道关闭之后还没有接收到想要的内容,这往往意味着大事不妙,肯定要进行特殊处理并进行修复。这时候使用msg,ok:=<-ch,如果是因为ch关闭而停止的阻塞,那么ok会为false,开发者最好能在对可能出现提前关闭的channel进行处理时使用ok来报错提示
升级二:
这里引入buffered channel和unbuffered channel 的概念,最基础的channel就是unbuffered channel,我们可以在定义的时候make(chan int, 9)来创建buffered channel。
加入了缓冲区的channel的发送者在缓冲区爆满之前是不会堵塞的,而接受者还是会在接收不到的时候堵塞,其实为换句话说,sender被阻塞的时候,其实是没有发送成功的,只有被另一端读走一个数据之后才算是send成功,unbuffered其实也算是一种buffered,只是buffer为1
高级装逼用法,nil类型和channel类型的channel,一般用处不大,但是也存在这种用法
标签:ch,编程,golang,并发,线程,go,新手,channel From: https://www.cnblogs.com/yangxiaoshuai/p/18320851