感谢分享这门专注于Go并发编程的课程计划!Go的并发模型确实强大,但深入理解其细节和陷阱对开发者至关重要。以下是一些专业观点和示例代码,供课程内容参考:
1. Goroutine 生命周期管理
避免无限制地启动goroutine,需考虑优雅退出和资源清理。
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d stopping\n", id)
return
default:
// 执行任务
fmt.Printf("Worker %d working\n", id)
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for i := 1; i <= 3; i++ {
go worker(ctx, i)
}
time.Sleep(3 * time.Second)
cancel() // 通知所有worker停止
time.Sleep(1 * time.Second)
}
2. Channel 使用模式
展示带缓冲channel和无缓冲channel的区别,以及关闭channel的最佳实践。
func producer(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
ch <- i
fmt.Printf("Produced: %d\n", i)
}
close(ch) // 生产者负责关闭channel
}
func consumer(ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for num := range ch {
fmt.Printf("Consumed: %d\n", num)
time.Sleep(100 * time.Millisecond)
}
}
func main() {
ch := make(chan int, 2) // 带缓冲channel
var wg sync.WaitGroup
wg.Add(2)
go producer(ch, &wg)
go consumer(ch, &wg)
wg.Wait()
}
3. 数据竞争检测与避免
使用sync包中的工具防止数据竞争。
type SafeCounter struct {
mu sync.RWMutex
value int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *SafeCounter) Value() int {
c.mu.RLock()
defer c.mu.RUnlock()
return c.value
}
func main() {
counter := SafeCounter{}
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Println("Final counter value:", counter.Value())
}
4. 并发模式示例
实现一个简单的扇出/扇入模式。
func generator(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func merge(channels ...<-chan int) <-chan int {
var wg sync.WaitGroup
out := make(chan int)
output := func(c <-chan int) {
defer wg.Done()
for n := range c {
out <- n
}
}
wg.Add(len(channels))
for _, c := range channels {
go output(c)
}
go func() {
wg.Wait()
close(out)
}()
return out
}
func main() {
in := generator(1, 2, 3, 4, 5)
// 扇出:多个goroutine处理同一channel
c1 := square(in)
c2 := square(in)
// 扇入:合并多个channel的结果
for n := range merge(c1, c2) {
fmt.Println(n)
}
}
5. Context 在并发中的应用
展示如何使用context传递取消信号和超时控制。
func process(ctx context.Context, data string) error {
select {
case <-time.After(2 * time.Second):
fmt.Printf("Processed: %s\n", data)
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
err := process(ctx, "test data")
if err != nil {
fmt.Println("Error:", err)
}
}
这些示例涵盖了Go并发编程的关键方面,包括goroutine管理、channel操作、数据安全、常见模式和context使用。课程中可以进一步探讨这些概念的组合使用、性能考量以及调试技巧。期待课程的发布!