目录
- 并发简介
- 并发与并行
- go 例程:并发的构建块
- 通道:go 例程之间的通信
- select 语句:管理多个通道
- 同步原语
- 并发模式
- 上下文包:管理取消和 超时。
- 最佳实践和常见陷阱**
1.并发简介
并发是同时处理多个任务的能力。在 go 中,并发性是一等公民,内置于该语言的核心设计中。 go 的并发方法基于通信顺序进程(csp),该模型强调进程之间的通信而不是共享内存。
2.并发与并行:
go 例程支持并发,这是独立执行进程的组合。
如果系统有多个 cpu 核心并且 go 运行时安排 go 例程并行运行,则可能会发生并行(同时执行)。
3。 go 例程:
并发的构建块是 go 例程,是由 go 运行时管理的轻量级线程。它是与其他函数或方法同时运行的函数或方法。 go 例程是 go 并发模型的基础。
主要特征:
- 轻量级:go 例程比操作系统线程轻得多。您可以轻松创建数千个 go 例程,而不会显着影响性能。
- 由 go 运行时管理:go 调度程序处理可用操作系统线程之间的 go 例程分配。
- 廉价创建:启动 go 例程就像在函数调用之前使用 go 关键字一样简单。
- 堆栈大小:go 例程从一个小堆栈(大约 2kb)开始,可以根据需要增长和缩小。
创建 go 例程:
要启动 go 例程,只需使用 go 关键字,后跟函数调用:
go functionname()
或者使用匿名函数:
go func() { // function body }()
go-routine 调度:
- go 运行时使用 m:n 调度程序,其中 m 个 go 例程被调度到 n 个操作系统线程上。
- 这个调度程序是非抢占式的,这意味着 go 例程在空闲或逻辑阻塞时会产生控制权。
通讯与同步:
- goroutine 通常使用通道进行通信,遵循“不要通过共享内存进行通信;通过通信来共享内存”的原则。
- 对于简单的同步,您可以使用像sync.waitgroup或sync.mutex这样的原语。
示例及说明:
package main import ( "fmt" "time" ) func printnumbers() { for i := 1; i <p><strong>说明:</strong></p>
- 我们定义了两个函数:printnumbers 和 printletters。
- 在 main 中,我们使用 go 关键字将这些函数作为 goroutine 启动。
- 然后 main 函数休眠 2 秒,让 goroutine 完成。
- 如果没有 goroutine,这些函数将按顺序运行。对于 goroutine,它们是同时运行的。
- 输出将显示数字和字母交错,演示并发执行。
goroutine 生命周期:
- goroutine 在使用 go 关键字创建时启动。
- 当其功能完成或程序退出时,它终止。
- 如果管理不当,goroutines 可能会泄漏,因此确保它们可以退出非常重要。
最佳实践:
- 不要在库中创建 goroutine;让调用者控制并发。
- 创建无限数量的 goroutine 时要小心。
- 使用通道或同步原语在 goroutine 之间进行协调。
- 考虑使用工作池来有效管理多个 goroutine。
带有 go 例程解释的简单示例
package main import ( "fmt" "time" ) // printnumbers is a function that prints numbers from 1 to 5 // it will be run as a goroutine func printnumbers() { for i := 1; i <p><strong>4.频道:</strong></p> <p>通道是 go 中的一项核心功能,它允许 go 例程相互通信并同步执行。它们为一个 go 例程提供了一种将数据发送到另一个 go 例程的方法。</p> <p><strong>频道的目的</strong></p> <p>go 中的通道有两个主要用途:<br> a) 通信:它们允许 goroutine 相互发送和接收值。<br> b) 同步:它们可用于跨 goroutine 同步执行。</p> <p>创建:使用 make 函数创建通道:<br></p> <pre class="brush:php;toolbar:false">ch := make(chan int) // unbuffered channel of integers
发送:使用
ch <p>接收:使用 </p> <pre class="brush:php;toolbar:false">value := <p><strong>频道类型</strong></p> <p>a) 无缓冲通道:</p>
- 创建时没有容量: ch := make(chan int)
- 发送块直到另一个 goroutine 接收到。
- 接收会阻塞,直到另一个 goroutine 发送。
ch := make(chan int) go func() { ch <p>b) 缓冲通道:</p>
- 使用容量创建: ch := make(chan int, 3)
- 当缓冲区已满时仅发送块。
- 仅当缓冲区为空时才阻塞接收。
ch := make(chan int, 2) ch <p><strong>频道方向</strong></p> <p>通道可以是定向的或双向的:</p>
- 双向:chan t
- 仅发送:chan
- 仅接收:
示例:
func send(ch chan <p><strong>关闭频道</strong></p> <p>可以关闭通道以表示不再发送任何值:<br></p> <pre class="brush:php;toolbar:false">close(ch)
从封闭通道接收:
如果通道为空,则返回通道类型的零值。
您可以使用二值接收来检查通道是否关闭:
value, ok := <p><strong>跨频道</strong></p> <p>您可以使用 for range 循环从通道接收值,直到通道关闭:<br></p> <pre class="brush:php;toolbar:false">for value := range ch { fmt.Println(value) }
嘿,感谢您坚持到最后!我感谢您成为有价值的读者和学习者。请在此处以及我的 linkedin 和 github 上关注我 .
以上就是Go 中的并发:从基础知识到高级概念的详细内容,更多请关注php中文网其它相关文章!
版权声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系 yyfuon@163.com