From dd9b607ebeff91caa4545ecbbbbb48237becb51e Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 7 Jul 2024 20:52:43 +0800 Subject: [PATCH] channel --- Concurrency/Concurrency | 28 --------------------- Concurrency/channel.go | 39 +++++++++++++++++++++++++++++ Concurrency/concurrency | 52 +++++++++++++++++++++++++++++++++++++++ Concurrency/gomaxprocs.go | 31 +++++++++++++++++++++++ 4 files changed, 122 insertions(+), 28 deletions(-) delete mode 100644 Concurrency/Concurrency create mode 100644 Concurrency/channel.go create mode 100644 Concurrency/concurrency create mode 100644 Concurrency/gomaxprocs.go diff --git a/Concurrency/Concurrency b/Concurrency/Concurrency deleted file mode 100644 index b688231..0000000 --- a/Concurrency/Concurrency +++ /dev/null @@ -1,28 +0,0 @@ -并发的介绍 -golang是天然支持高并发的语言 -并发:同一时间内执行多个任务 -并行:同一时刻执行多个任务 - -golang的并发通过goroutine实现,goroutine是用户态的线程,由go的运行时runtime调度,而线程是通过操作系统去调度。 -最终还是放在操作系统的线程去执行,只不过管理(上下文切换)放在用户态,所以开销较小。 - -golang提供channel用来在多个goroutine之间进行通信。 - - - -只需要在调用函数前加上 go 关键字 即可开启一个goroutine - - -goroutine对应的函数执行结束了,goroutine就结束了 -main函数执行完毕,由main函数创建的那些goroutine就结束了 - -如何等待所有的goroutine结束之后再执行主函数? -sync.waitGroup对象中有三个方法 -var wg sync.waitGroup -wg.add(1) //计数器加1 -wg.done()//计数器减1 -wg.wait()//等待所有的goroutine结束 - - -goroutine与线程 -os线程有固定的栈内存 \ No newline at end of file diff --git a/Concurrency/channel.go b/Concurrency/channel.go new file mode 100644 index 0000000..ddfca28 --- /dev/null +++ b/Concurrency/channel.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "sync" +) + +// 通道的声明 +var c chan int //需要指定通道中元素的类型,引用类型,需要初始化 +var wait sync.WaitGroup + +func noBufferedChannel() { + c = make(chan int) //不带带缓冲区的通道初始化 + wait.Add(1) + go func() { + defer wait.Done() + x := <-c //接受 + fmt.Println("从通道C中取得值:", x) + }() + c <- 10 //发送 + wait.Wait() +} + +func bufferedChannel() { + c = make(chan int, 1) //带缓冲区的初始化 + c <- 10 + fmt.Println("10发送到通道中了") + x := <-c + fmt.Println("从通道C中取到值", x) + c <- 20 + fmt.Println("20发送到通道中了") + z := <-c + fmt.Println("从通道C中取到值", z) + close(c) +} + +func main() { + bufferedChannel() +} diff --git a/Concurrency/concurrency b/Concurrency/concurrency new file mode 100644 index 0000000..e56e0b9 --- /dev/null +++ b/Concurrency/concurrency @@ -0,0 +1,52 @@ +并发的介绍 +golang是天然支持高并发的语言 +并发:同一时间内执行多个任务 +并行:同一时刻执行多个任务 + +golang的并发通过goroutine实现,goroutine是用户态的线程,由go的运行时runtime调度,而线程是通过操作系统去调度。 +最终还是放在操作系统的线程去执行,只不过管理(上下文切换)放在用户态,所以开销较小。 + +golang提供channel用来在多个goroutine之间进行通信。 + + + +只需要在调用函数前加上 go 关键字 即可开启一个goroutine + +goroutine什么时候结束? + +goroutine对应的函数执行结束了,goroutine就结束了 +main函数执行完毕,由main函数创建的那些goroutine就结束了 + +如何等待所有的goroutine结束之后再执行主函数? +sync.waitGroup对象中有三个方法 +var wg sync.waitGroup +wg.add(1) //计数器加1 +wg.done()//计数器减1 +wg.wait()//等待所有的goroutine结束 + + +goroutine与线程 +os线程有固定的栈内存。一般是2MB,一个goroutine的生命周期开始的时候占用的内存是2kb +goroutine的栈内存不是固定的,可以按需扩大或者缩小,最大1Gb + + +goroutine的调度 +G: 即goroutine,里面除了存放本goroutine的信息之外还有与所在的p的绑定等信息。 +M: machine是go运行时对操作系统线程内核线程的虚拟,M与内核线程一般是一一映射的关系,一个goroutine最终是要放到M上 +去运行的。 +P: P管理着一组goroutine队列,P里面会存储当前goroutine运行的上下文环境(函数指针,堆栈地址,以及地址边界),P会对自己管理的goroutine队列做一些调度 +当自己的队列消费完成之后就去全局队列里面取,如果全局队列里也消费完了回去其他P的队列里抢任务。 + + +P和M一般也是一一对应的,他们的关系是:P管理着一组G挂载在M上运行,当一个G长久阻塞在一个M上时,runtime会新建一个M,阻塞G所在的P会把其他的G挂载在新的M上, +当旧的G阻塞完成或者认为其已经死掉时,回收旧的M。 + + +P的个数通过runtime.GOMAXPROC指定,最大256,GO1.5版本后默认为物理线程数,在并发量大的时候最增加一些P和M,但不会太多 + +M:N 复用/调度M的goroutine的到N个os线程 + + +一个操作系统的线程对应多个用户态的goroutine +狗程序可以同时使用多个操作系统线程 +goroutine和os线程时多对多的关系,即M:N diff --git a/Concurrency/gomaxprocs.go b/Concurrency/gomaxprocs.go new file mode 100644 index 0000000..dbdbc50 --- /dev/null +++ b/Concurrency/gomaxprocs.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "runtime" + "sync" +) + +var wgGroup sync.WaitGroup + +func main() { + runtime.GOMAXPROCS(2) //指定P的数量 + wgGroup.Add(2) + go a() + go b() + wgGroup.Wait() +} + +func a() { + defer wgGroup.Done() + for i := 0; i < 10; i++ { + fmt.Printf("A:%v\n", i) + } +} + +func b() { + defer wgGroup.Done() + for i := 0; i < 10; i++ { + fmt.Printf("B:%v\n", i) + } +}