目录
前言
并发和并行
协程
协程关键字 go
使用sync.WaitGroup进行协程阻塞
有了协程,那协程之间如何通讯呢? (内存共享/数据共享)
全局变量进行通讯 (遇到的问题,如何解决)
channel通道实例
前言
自学golang,知识点理解,整理,代码亲自实践分享。(如果哪里不懂,或者写的有问题,欢迎指出,一起进步)
并发和并行
并发(concurrency)与并行(parallelism)不同。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了(Golang 的并发通过切换多个线程达到减少物理处理器空闲等待的目的)。在很多情况下,并发的效果比并行好,因为操作系统和硬件的总资源一般很少,但能支持系统同时做很多事情。这种 "使用较少的资源做更多的事情" 的哲学,也是指导 Golang 设计的哲学。
如果希望让 goroutine 并行,必须使用多于一个逻辑处理器。当有多个逻辑处理器时,调度器会将 goroutine 平等分配到每个逻辑处理器上。这会让 goroutine 在不同的线程上运行。不过要想真的实现并行的效果,用户需要让自己的程序运行在有多个物理处理器的机器上。否则,哪怕 Golang 运行时使用多个线程,goroutine 依然会在同一个物理处理器上并发运行,达不到并行的效果。
深度理解GMP模型链接参考:
协程
协程关键字 go
//执行该结果就会导致,有可能不能输出hello:当主进程已经执行完,协程未执行完,该程序已经结束;如果给主进行设置sleep可等待协程。
func Handle() {
go func() {
fmt.Print("hello")
}()
fmt.Print("world")
}
使用sync.WaitGroup进行协程阻塞
//可使用sync.WaitGroup进行协程阻塞
func Handle1() {
var wg sync.WaitGroup
wg.Add(2)
//此时两个协程的执行顺序是乱序的;
go func() {
defer wg.Done()
fmt.Print("hello11")
}()
go func() {
defer wg.Done()
fmt.Print("hello22")
}()
wg.Wait()
fmt.Print("world")
}
有了协程,那协程之间如何通讯呢? (内存共享/数据共享)
//此时有了协程,那协程之间如何通讯呢?于是就有了channel
func Handle2() {
ch := make(chan int) //声明通道
ch <- 10 //通道的接受
var num = <-ch //通道的发送
close(ch) //通道的关闭
fmt.Print(num)
}
全局变量进行通讯 (遇到的问题,如何解决)
//当然也可以使用全局变量进行通讯,会遇到什么问题呢?见代码
func Handle3() {
var wg sync.WaitGroup //声明结构体,就相当于声明php中的类
//var lock sync.Mutex
var a int
wg.Add(2)
go func() { //单个结果:5000
defer wg.Done()
for i := 0; i < 5000; i++ {
//lock.Lock()//加锁(调用结构体中的公有方法【首字母大写】,就类似于php调用类中的公有方法)
a += 1
//lock.Unlock()//解锁
}
}()
go func() { //单个结果:5000
defer wg.Done()
for i := 0; i < 5000; i++ {
//lock.Lock()
a += 1
//lock.Unlock()
}
}()
//a的结果为什么不是10000呢?
//原因:2个协程之间是并发关系,对同一块地址操作时,会发生争抢的情况。
//解决办法:我们可以使用加锁的方式进行解决争抢的情况。(把加锁注释的代码放开)
wg.Wait()
fmt.Print(a)
}
channel通道实例
//golang中通道(管道)channel就是用来协程间通讯的
//channel通道有:无缓冲的通道,有缓冲的通道,单项通道
//无缓冲的通道:当通道中无数据时,是不能进行发送的;有数据时,是不能进行接受的。(都会进行阻塞)
//实例:
func Handle4() {
ch := make(chan int)
//ch := make(chan int,5)
for i := 0; i < 5; i++ {
go func() {
ch <- 10
fmt.Println("channel接受值;")
}()
}
time.Sleep(time.Second * 3)
a := <-ch
fmt.Println("channel发送值:", a)
//执行该结果本以为主程序有了sleep,结果应该是5次的"channel接受值"和一个"channel发送值:10",循环导致
//然而,因为无缓冲的通道会进行阻塞,有值时,阻塞写不进去,无值时,阻塞取值取不出。
//可以尝试将 ch := make(chan int) 修改为 ch := make(chan int,5)
}