go并发的基础知识

  • Channel

    • 是阻塞同步的
    • 通过make创建,close关闭
    • Channel是引用类型
    • 可以使用for range 来迭代不断操作channel
    • 可以设置单向或双向通道
    • 可以设置缓存大小,在未被填满前不会发生阻塞
  • Select

    • 可以处理一个或多个channel的发送与接收
    • 同时有多个可用的channel时按随机顺序处理
    • 可用空的select来阻塞main函数
    • 可设置超时

一个简答的例子

...
func main(){
	go work()
}
func work(){
	fmt.Println("Go!")
}

输入:
(什么都没有)

什么都没有输出,原因是由代码可以看出,启动了一个携程,在work函数还没有打印主函数已经结束了。

为了让work里的打印可以输出,让主线程睡1秒中,这是为了让携程可以执行完毕,代码修改如下:

...
func main(){
	go work()
	time.sleep(time.Second)
}
func work(){
	fmt.Println("Go!")
}

以上仅仅是为了效果,在实际的开发中不会这样做,因为我们无法判断work函数的执行逻辑到底需要多长时间。
借助Channel,替换time.sleep

package main

import (
	"fmt"
)

func main() {
	c:= make(chan bool)
	go work(c)
	<- c //这里会阻塞,直到c里有值
}

func work(c chan bool){
	fmt.Println("Go Go Go!")
	c <- true
}

输出:
Go Go Go !

注意:以上是个简单的程序,只向channel放了一个值,当取出后,资源就会自动释放了,程序就结束了,所以不用再调用close关闭通道了。

上面的程序从通道里取值,没有赋值给任何变量也没有输出,如下使用range从通道里将值打印出来:

package main

import (
	"fmt"
)

func main() {
	c:= make(chan bool)
	go work(c)
	<- c

	for v:= range c{
		fmt.Println(v)
	}
}

func work(c chan bool){
	fmt.Println("Go Go Go!")
	c <- true
	close(c)
}

输出:
Go Go Go!
true

以上程序修改了:11-13行使用range 将值打印出来, 19行调用了close函数关闭通道,如果不关闭通道,就会不断的遍历通道造成死锁。
for i := range c能够不断的读取channel里面的数据,直到该channel被显式的关闭。关闭channel之后就无法再发送任何数据了,在消费方可以通过语法v,ok := <-ch测试channel是否被关闭。如果ok返回false,那么说明channel已经没有任何数据并且已经被关闭。

设置有缓存的通道
c:= make(chan bool,1)
有缓存的就是channel可以存储多少元素。ch:= make(chan bool, 4),创建了可以存储4个元素的bool 型channel。在这个channel 中,前4个元素可以无阻塞的写入。当写入第5个元素时,代码将会阻塞,直到其他goroutine从channel 中读取一些元素,腾出空间。
有缓存和无缓存的区别:有缓存的是异步的,无缓存是同步阻塞的。如下示例:

package main

import (
	"fmt"
)

func main() {
	c:= make(chan bool,1)
	go func(){
		fmt.Println("Go Go Go!")
		<- c
	}()
	c <- true
}

以上程序不会有任何输出,以上创建了有缓存的通道,在执行14行的时候,程序不会阻塞,就不会等待携程的执行。

package main

import (
	"fmt"
)

func main() {
	c:= make(chan bool,1)
	go func(){
		fmt.Println("Go Go Go!")
		c <- true
	}()
	<- c
}

输出:
Go Go Go!

缓存通道的例子

package main

import (
	"fmt"
	"runtime"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	c := make(chan bool,10)
	for i := 0; i < 10; i++ {
		go Go(c, i)
	}
	for i := 0; i < 10; i++ {
		<-c
	}
}

func Go(c chan bool, index int) {
	a := 1

	for i := 0; i <= 10000000; i++ {
		a += i
	}
	fmt.Println(index, a)
	c <- true
}

实现以上程序的另一个办法:

package main

import (
	"fmt"
	"sync"
)

func main() {
	wg:= sync.WaitGroup{}
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go Go(&wg, i)
	}
	wg.Wait()
}

func Go(wg *sync.WaitGroup, index int) {
	a := 1
	for i := 0; i <= 10000000; i++ {
		a += i
	}
	fmt.Println(index, a)
	wg.Done()
}

输出:
0 50000005000001
5 50000005000001
9 50000005000001
1 50000005000001
7 50000005000001
6 50000005000001
3 50000005000001
2 50000005000001
4 50000005000001
8 50000005000001

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值