并发与并行的区别:
区别:
1. 并发:☞逻辑上具备同时处理多个任务的能力,指的是多个任务在同一时间段执行而不是同一时刻
2. 并行:☞物理上同一时刻执行多个任务
goroutine:
goroutine像一个多线程和协程的综合体,运行时会创建多个限制来执行并发任务,且任务单元可调度到其他线程并行执行,最大限度提升执行效率。
go关键字
go println("hello world")
go funct(s){
println(s)
}("hello world")
创建并发任务通过go关键字就可,但是关键字go并非执行并发操作,而是创建一个并发任务单元,放置于系统队列中等待调度器调度执行。等待执行过程中,当前流程不会阻塞,也不会等待该任务启动,存在多个任务时也不会去保证并发任务的执行次序。
每个任务单元相比系统线程栈的MB级别来说小了很多,goroutine定义栈初始只需要2KB。自定义栈采用按需分配的策略,在需要时进行扩容,最大能达到GB规模。
go关键字与defer一样,会因为”延迟执行“而立即计算并复制执行参数,可参考下面例子:
package main
import "time"
var c int
func counter() int {
c++
return c
}
func main() {
a :=
go func(x, y int) {
time.Sleep(time.Second)
println("go:", x, y)
}(a, counter())
a +=
println("main:", a, counter())
time.Sleep(time.Second *)
}
//输出结果:
main:
go:
通道
Go内置CSP模型,且鼓励使用CSP通道,以通信来代替内存共享,实现并发安全,不需要开发人员自行维护数据一致和完整性。
channel是显式的,收发双方必须都知道数据类型和具体通道。
channel从底层实现上来说是一个队列,同步模式下收发双方必须配对,然后直接复制数据给对方,配对失败则置入等待队列,直到出现适配的另一方
异步模式抢夺的是数据缓冲槽,发送方要求有空草可供写入,接收方要求有缓冲数据可读。
通道除了传递数据之外,通常也被用作事件通知。
func main(){
done := make(chan struct{}) //结束事件
c := make(chan string) //数据传输通道
go func(){
s:=<-c //接受数据
println(s)
close(done) //关闭通道,作为结束事件通知
}()
c <- "hi!" //发送数据
<-done //阻塞,置入等待 等待数据或事件通知
}
异步模式
可以使用len以及cap函数来获取缓冲区的大小以及缓冲区已缓冲的数量
对于同步模式的channel使用len以及cap返回结果均为0,此不同可用作区分channel是同步还是异步
import "unsafe"
func main(){
c := make(chan int) //创建一个带3个缓冲槽的异步通道
c
c
println("通道中第一个值: ",<-c) //取出第一个数据
println("通道中第二个值: ",<-c) //取出第二个数据
println("通道中写入值的数量: ",len(c))
println("通道的容积: ",cap(c))
println("通道变量的地址: ",c,"通道的长度: ",unsafe.Sizeof(c))
}
//输出
//通道中第一个值: 1
//通道中第二个值: 2
//通道中写入值的数量: 0
//通道的容积: 3
//通道变量的地址: 0xc42006a000 通道的长度: 8