golang 中 goroutines 和 channels 的高级用法
在 Golang 的并发编程中,Goroutines 和 Channels 是两个非常重要的概念。Goroutines 是轻量级线程,可以并发执行,而 Channels 则是 Goroutines 之间通信的机制。在这篇文章中,我们将探讨 golang 中 goroutines 和 channels 的高级用法,并通过代码示例来说明。
一、Goroutines 的高级用法
- 可以通过 select 语句来实现 Goroutines 的多路复用。下面的代码示例中,我们创建了两个 Goroutines,分别用于计算斐波那契数列和阶乘。通过 select 语句,我们可以等待两个 Goroutines 同时完成,并将计算结果打印出来。
package main
import (
"fmt"
)
func fibonacci(n int, c chan<- int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func factorial(n int, c chan<- int) {
result := 1
for i := 1; i <= n; i++ {
result *= i
}
c <- result
close(c)
}
func main() {
fibChan := make(chan int)
factChan := make(chan int)
go fibonacci(10, fibChan)
go factorial(5, factChan)
for {
select {
case fib, ok := <-fibChan:
if ok {
fmt.Println("Fibonacci:", fib)
} else {
fibChan = nil
}
case fact, ok := <-factChan:
if ok {
fmt.Println("Factorial:", fact)
} else {
factChan = nil
}
default:
if fibChan == nil && factChan == nil {
return
}
}
}
}- 可以通过 WaitGroup 来等待 Goroutines 的完成。WaitGroup 是一个计数器,可以用于等待一组 Goroutines 的结束。下面的代码示例中,我们创建了两个 Goroutines,分别用于计算斐波那契数列和阶乘。通过 sync.WaitGroup,我们可以等待两个 Goroutines 同时完成。
package main
import (
"fmt"
"sync"
)
func fibonacci(n int, c chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func factorial(n int, c chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
result := 1
for i := 1; i <= n; i++ {
result *= i
}
c <- result
close(c)
}
func main() {
fibChan := make(chan int)
factChan := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go fibonacci(10, fibChan, &wg)
go factorial(5, factChan, &wg)
go func() {
wg.Wait()
close(fibChan)
close(factChan)
}()
for {
select {
case fib, ok := <-fibChan:
if ok {
fmt.Println("Fibonacci:", fib)
} else {
fibChan = nil
}
case fact, ok := <-factChan:
if ok {
fmt.Println("Factorial:", fact)
} else {
factChan = nil
}
default:
if fibChan == nil && factChan == nil {
return
}
}
}
}二、Channels 的高级用法
- 可以通过设置缓冲区大小来控制 Channel 的阻塞行为。默认情况下,Channel 是无缓冲的,即发送和接收都会阻塞直到对方准备好。我们可以通过 make 函数的第二个参数来设置缓冲区大小。下面的代码示例中,我们创建了一个拥有缓冲区大小为 3 的 Channel,并向其中发送了 3 个值。由于缓冲区未满,发送不会阻塞。
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}- 可以通过 range 关键字来迭代 Channel。range 关键字可以用于迭代 Channel 中的值,当 Channel 关闭时,迭代会自动结束。下面的代码示例中,我们创建了一个计数器 Goroutines,并向一个无缓冲的 Channel 中发送了 5 个值。在 main 函数中,我们通过 range 关键字来迭代 Channel 中的值,并将其打印出来。当 Channel 关闭后,range 循环会自动结束。
package main
import (
"fmt"
"time"
)
func counter(ch chan<- int) {
for i := 1; i <= 5; i++ {
ch <- i
time.Sleep(time.Second)
}
close(ch)
}
func main() {
ch := make(chan int)
go counter(ch)
for val := range ch {
fmt.Println(val)
}
}综上所述,Golang 中的 Goroutines 和 Channels 提供了强大且灵活的并发编程能力。通过选择语句、WaitGroup、缓冲区和 range 关键字等高级用法,我们可以更好地控制 Goroutines 和 Channels 的行为。希望本文所给出的代码示例能够帮助读者更好地理解和应用这些高级用法。
立即学习“go语言免费学习笔记(深入)”;










