Go语言是一门支持并发的编程语言,通过goroutine和channel两种核心机制实现并发编程。下面分以下步骤详细讲解Go语言中并发的工作原理。
1. goroutine
goroutine是Go语言实现并发的基本单位。它类似于线程,但相较于线程开销更小,能够更好地利用多核心CPU的优势。与线程不同的是,Goroutine通过Go语言的运行时系统进行调度,相比于操作系统的调度更加轻量级和高效。
1.1 创建goroutine
使用关键词go
创建goroutine,如下:
go func() {
// goroutine的内容
}()
此时程序会在当前goroutine执行该语句,并开启一个新的goroutine去执行函数里的内容。
1.2 goroutine调度
在Go语言中,多个goroutine并发执行时,对应的运行时系统负责把每个goroutine分配到不同的逻辑处理器(P)上进行执行。每个P包含一个固定数量的操作系统线程M,操作系统线程M负责执行goroutine。当一个goroutine中的I/O阻塞时,对应的线程M将会被剥离,寻求其他可以执行的goroutine。
1.3 示例说明
下面是一个简单的示例:
package main
import (
"fmt"
"time"
)
func say(str string) {
for i := 0; i < 5; i++ {
fmt.Println(str)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
go say("hello")
say("world")
}
在该程序中,我们创建了一个名为say
的函数,其中包含一个for
循环和一个time.Sleep()
函数。在main
函数中,我们使用关键词go
创建了一个goroutine,另一个没有使用go
创建,因此它在主goroutine中运行。
运行该程序,可以看到两个函数的输出交替进行(因为每次输出后都sleep了100毫秒),说明这两个goroutine并发执行。
2. channel
goroutine基于channel进行通信,channel是一个类似于队列的数据结构。goroutine通过channel来收发数据以保持同步和避免竞争条件。
2.1 创建channel
使用make
函数创建channel,语法如下:
make(chan T)
其中,T
是channel中存放的元素类型。
2.2 发送与接收
使用<-
操作符进行数据的发送和接收。发送语法如下:
ch <- x
其中,ch
是channel,x
是要发送的值。
接收语法如下:
x := <-ch
其中,x
是接收到的值,ch
是要接收数据的channel。
2.3 示例说明
下面是一个示例,其中包含了一个发送方和一个接收方,它们通过无缓冲的channel进行通信:
package main
import (
"fmt"
"time"
)
func pinger(c chan<- string) {
for i := 0; ; i++ {
c <- "ping"
}
}
func printer(c <-chan string) {
for {
msg := <-c
fmt.Println(msg)
time.Sleep(time.Second)
}
}
func main() {
var c chan string = make(chan string)
go pinger(c)
go printer(c)
for {
time.Sleep(time.Second)
}
}
在该程序中,我们创建了两个函数pinger
和printer
,它们的参数分别是只发送和只接收的channel。我们使用关键词go
创建了两个goroutine,它们并发执行。
在pinger
函数中,我们不断向channel发送值"ping"
。在printer
函数中,我们不断接收来自channel的值并在屏幕上打印输出。在main
函数中,我们使用make
函数创建channel,然后启动了两个不同的goroutine。因为pinger
函数会不断地向channel发送数据,所以我们需要用一个无限循环来防止主函数退出。运行该程序可以看到,不断输出ping
字符串,说明两个goroutine之间通过channel实现了通信。
以上就是Go语言中并发的工作原理的完整攻略。通过上述步骤可以清晰地了解Go语言中的并发原理,并且讲解了其中两个重要的示例说明。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go语言中并发的工作原理 - Python技术站