Golang协程(Goroutine)与通道(Channel)教程
我刚接触Golang的并发编程,对Goroutine和Channel的使用有些困惑。请问:
- Goroutine和普通线程有什么区别?为什么说它更轻量级?
- Channel在实际项目中通常用来解决哪些问题?能不能举个典型的生产者-消费者例子?
- 带缓冲的Channel和不带缓冲的Channel在使用上有什么需要注意的地方?
- 如何避免Goroutine泄漏?有没有什么最佳实践?
- 当多个Goroutine同时往Channel写数据时,会发生数据竞争吗?需要加锁吗? 希望能得到一些实际代码示例和最佳实践建议,谢谢!
Go语言的协程(Goroutine)和通道(Channel)是其核心特性。协程是一种轻量级线程,由Go runtime管理,创建成本低,调度高效。
创建协程:使用go
关键字。例如:
go func() {
fmt.Println("这是一个协程")
}()
注意,协程启动后,主函数可能已经结束,需确保协程执行完毕。
通道(Channel):用于协程间通信。定义时需指定数据类型,如chan int
。支持发送(<-
)和接收操作。
基本用法:
- 声明与初始化:
ch := make(chan int)
- 发送与接收:
ch <- 42 // 发送 value := <-ch // 接收
- 带缓冲的通道:
ch := make(chan int, 5) // 缓冲区大小为5
关闭通道:使用close(ch)
,发送方应避免在关闭后继续写入。
select语句:用于多路复用,类似switch-case。
select {
case v := <-ch:
fmt.Println(v)
default:
fmt.Println("通道未准备好")
}
注意事项:死锁和数据竞争是常见问题,务必确保发送与接收匹配,使用sync
包避免竞态。通过这些工具,Go能高效处理并发任务。
更多关于Golang协程(Goroutine)与通道(Channel)教程的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Go语言的协程(Goroutine)和通道(Channel)是其核心特性。Goroutine是轻量级线程,由Go runtime管理,通过go
关键字启动,非常高效。
使用示例:
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("goroutine") // 启动一个协程
say("main") // 主协程继续执行
}
通道(Channel)用于协程间的通信和同步。声明格式:chan<-
发送,<-chan
接收。
示例:
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // 发送结果到通道
}
func main() {
a := []int{2, 3, 4}
c := make(chan int) // 创建通道
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // 接收两个协程的结果
fmt.Println(x + y)
}
常用操作包括缓冲通道、关闭通道、select语句处理多通道等。记住,使用close()
关闭通道,并用for-range
安全读取数据,避免资源泄漏。
Golang协程(Goroutine)与通道(Channel)教程
Goroutine(协程)
Goroutine是Go语言的轻量级线程实现,由Go运行时管理。创建协程非常简单:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world") // 创建一个新协程
say("hello") // 主协程
}
Channel(通道)
Channel是Goroutine之间的通信机制,可以安全地传递数据:
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将sum发送到通道c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int) // 创建通道
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从通道接收
fmt.Println(x, y, x+y)
}
通道类型
-
无缓冲通道:发送和接收会阻塞直到另一方准备好
ch := make(chan int)
-
缓冲通道:可以存储有限数量的值
ch := make(chan int, 100)
关闭通道
close(ch) // 关闭通道
v, ok := <-ch // ok为false表示通道已关闭
选择语句(select)
select {
case v := <-ch1:
fmt.Println("收到", v)
case ch2 <- x:
fmt.Println("发送", x)
default:
fmt.Println("没有通信")
}
协程和通道是Go并发模型的核心,它们使并发编程变得简单而高效。