目录
定义与特点:
使用方法:
go
关键字后跟一个函数调用,即可启动一个Goroutine。go myFunction()
package main
import (
"fmt"
"time"
)
// 定义一个简单的函数
func printNumbers(prefix string) {
for i := 1; i <= 5; i++ {
fmt.Println(prefix, i)
// 休眠一段时间,以模拟实际操作中的耗时
time.Sleep(time.Millisecond * 500)
}
}
func main() {
// 使用 go 关键字启动一个新的 Goroutine
go printNumbers("Goroutine")
// 主Goroutine也执行相同的函数
printNumbers("Main")
// 等待足够长的时间以确保Goroutine完成
// 注意:这不是同步Goroutines的推荐方式
// 后续课程将介绍更好的方法(如WaitGroup或Channel)
time.Sleep(time.Second * 3)
fmt.Println("主函数执行完毕")
}
- 函数定义:
printNumbers
函数接受一个字符串参数prefix
,并打印出该前缀下的数值序列。- 启动Goroutine:使用
go
关键字启动printNumbers
函数作为一个新的Goroutine。这意味着printNumbers("Goroutine")
将并行执行。- 主Goroutine:主函数
main
本身也是一个Goroutine。在这里,它调用printNumbers("Main")
,同样执行数值打印操作。- 并行执行:您会看到,"Goroutine"和"Main"的输出是交替出现的,显示了两个Goroutine是同时运行的。
- 等待结束:使用
time.Sleep
暂时等待Goroutine完成。这是为了演示目的;实际应用中我们会使用更加精确的同步机制。
time.Sleep
来等待Goroutines完成,而是使用像通道(Channels)或sync.WaitGroup
这样的同步机制。?
定义与作用:
类型与使用:
ch := make(chan int)
(无缓冲)或ch := make(chan int, 5)
(有缓冲,容量为5)。<-
操作符向Channel发送或接收数据。?
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个无缓冲的Channel
ch := make(chan string)
// 启动一个Goroutine,发送数据到Channel
go func() {
fmt.Println("Goroutine开始发送数据")
ch <- "从Goroutine传来的消息"
}()
// 模拟延时,表示主Goroutine正在处理其他任务
time.Sleep(2 * time.Second)
// 从Channel接收数据
message := <-ch
fmt.Println("接收到数据:", message)
// 创建一个有缓冲的Channel,容量为2
bufferedCh := make(chan int, 2)
// 向有缓冲的Channel发送数据,不会立即阻塞
bufferedCh <- 1
bufferedCh <- 2
// 从有缓冲的Channel接收数据
fmt.Println("从有缓冲Channel接收数据:", <-bufferedCh)
fmt.Println("从有缓冲Channel接收数据:", <-bufferedCh)
}
- 无缓冲Channel:
ch := make(chan string)
创建了一个无缓冲的Channel,用于传递字符串类型的数据。- 发送数据到Channel:Goroutine中使用
ch <- "从Goroutine传来的消息"
向Channel发送数据。此时,如果没有接收者,发送操作会阻塞。- 接收Channel数据:主Goroutine中使用
message := <-ch
接收数据。接收操作会阻塞直到有数据到达。- 有缓冲Channel:
bufferedCh := make(chan int, 2)
创建了一个容量为2的有缓冲Channel。- 向有缓冲Channel发送数据:发送操作在Channel未满时不会阻塞。
- 从有缓冲Channel接收数据:即使发送Goroutine已经结束,数据仍然可以从Channel中被接收。
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
// 数据处理函数
// 模拟接收一个整数,经过处理后发送到输出Channel
func processData(id int, data int, out chan<- string) {
// 模拟数据处理耗时
time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
result := fmt.Sprintf("Goroutine %d 处理结果:%d", id, data*2) // 假设处理是简单的乘以2
out <- result
}
func main() {
// 初始化随机种子
rand.Seed(time.Now().UnixNano())
// 创建一个无缓冲的Channel
dataCh := make(chan string)
// 使用WaitGroup等待所有Goroutines完成
var wg sync.WaitGroup
// 启动多个Goroutines进行数据处理
const numGoroutines = 5 // Goroutines的数量
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
data := rand.Intn(100) // 生成一个随机数作为数据
processData(id, data, dataCh)
}(i)
}
// 启动一个Goroutine用于接收所有处理结果
go func() {
wg.Wait()
close(dataCh)
}()
// 从Channel中读取并打印每个Goroutine的处理结果
for result := range dataCh {
fmt.Println(result)
}
fmt.Println("所有Goroutine处理完成")
}
processData
函数:每个Goroutine都会调用这个函数,它接收一个整数数据,处理后(这里简化为乘以2的操作),将结果发送到输出Channel。
启动多个Goroutines:循环中创建了多个Goroutines,每个都调用processData
函数处理数据。
使用sync.WaitGroup
:WaitGroup
用于等待所有Goroutine完成其工作。每启动一个Goroutine,就调用wg.Add(1)
,每个Goroutine完成时调用wg.Done()
。
关闭Channel:在所有Goroutines完成后,关闭数据Channel。这是通过在另一个Goroutine中调用wg.Wait()
和close(dataCh)
实现的。
读取Channel数据:主Goroutine循环读取Channel中的数据,并打印结果。