golang多种退出模式

golang多种退出模式

1. 基于 channel 的退出模式

通过共享的 channel 发送退出信号,其他 goroutine 监听该信号并决定何时退出。

示例:

package main

import (
	"fmt"
	"time"
)

func worker(id int, quit chan bool) {
	for {
		select {
		case <-quit:
			fmt.Printf("Worker %d: exiting\n", id)
			return
		default:
			fmt.Printf("Worker %d: working\n", id)
			time.Sleep(time.Second)
		}
	}
}

func main() {
	quit := make(chan bool)
	
	// 启动多个 worker goroutines
	for i := 1; i <= 3; i++ {
		go worker(i, quit)
	}
	
	// 主 goroutine 等待一段时间后发送退出信号
	time.Sleep(5 * time.Second)
	close(quit)  // 发送退出信号,所有 worker 会收到并退出
	
	// 等待一段时间,确保所有 worker 都退出
	time.Sleep(1 * time.Second)
}

在此示例中,主 goroutine 在 5 秒后关闭 quit 通道,通知所有 worker goroutine 退出。

2. 基于 context 的退出模式

使用 context 来管理 goroutine 的生命周期,支持超时和取消操作。

示例:

package main

import (
	"context"
	"fmt"
	"time"
)

func worker(ctx context.Context, id int) {
	for {
		select {
		case <-ctx.Done():
			fmt.Printf("Worker %d: exiting, reason: %v\n", id, ctx.Err())
			return
		default:
			fmt.Printf("Worker %d: working\n", id)
			time.Sleep(time.Second)
		}
	}
}

func main() {
	// 创建一个可以取消的 context
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()  // 确保超时后 cancel 被调用
	
	// 启动多个 worker goroutines
	for i := 1; i <= 3; i++ {
		go worker(ctx, i)
	}
	
	// 主 goroutine 等待一段时间后取消 context
	time.Sleep(5 * time.Second)
	cancel()  // 取消 context,所有 worker 会收到退出信号
	
	// 等待一段时间,确保所有 worker 都退出
	time.Sleep(1 * time.Second)
}

在此示例中,主 goroutine 在 5 秒后调用 cancel(),通知所有 worker goroutine 退出。

3. 基于超时的退出模式

使用 context.WithTimeout 设置超时时间,超时后自动取消上下文,适用于需要在一定时间内完成任务的场景。

示例:

package main

import (
	"context"
	"fmt"
	"time"
)

func worker(ctx context.Context, id int) {
	for {
		select {
		case <-ctx.Done():
			fmt.Printf("Worker %d: exiting due to timeout, reason: %v\n", id, ctx.Err())
			return
		default:
			fmt.Printf("Worker %d: working\n", id)
			time.Sleep(time.Second)
		}
	}
}

func main() {
	// 创建一个带超时的 context,设置超时时间为 3 秒
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()  // 确保超时后 cancel 被调用
	
	// 启动多个 worker goroutines
	for i := 1; i <= 3; i++ {
		go worker(ctx, i)
	}
	
	// 等待超时,所有 worker 会自动收到退出信号
	time.Sleep(5 * time.Second)
}

在此示例中,主 goroutine 创建了一个 3 秒后自动取消的上下文,所有 worker goroutine 会在超时后自动退出。

4. 基于 sync.WaitGroup 的退出模式

使用 sync.WaitGroup 等待一组 goroutine 执行完毕,确保所有 goroutine 完成后再退出主程序。

示例:

package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done()  // 当 goroutine 完成时调用 Done()

	for i := 0; i < 3; i++ {
		fmt.Printf("Worker %d: working\n", id)
		time.Sleep(time.Second)
	}

	fmt.Printf("Worker %d: done\n", id)
}

func main() {
	var wg sync.WaitGroup
	
	// 启动多个 worker goroutines
	for i := 1; i <= 3; i++ {
		wg.Add(1)  // 为每个 goroutine 增加计数
		go worker(i, &wg)
	}

	// 等待所有 worker 完成
	wg.Wait()
	fmt.Println("All workers finished.")
}

在此示例中,主 goroutine 使用 sync.WaitGroup 等待所有 worker goroutine 完成后再退出。5. 基于 defer 的退出模式在 goroutine 中使用 defer 语句来确保在退出时执行清理操作。

示例:

package main

import (
	"fmt"
	"time"
)

func worker(id int) {
	defer fmt.Printf("Worker %d: done\n", id)  // 当 goroutine 退出时执行
	for i := 0; i < 3; i++ {
		fmt.Printf("Worker %d: working\n", id)
		time.Sleep(time.Second)
	}
}

func main() {
	// 启动多个 worker goroutines
	for i := 1; i <= 3; i++ {
		go worker(i)
	}

	// 等待一段时间,确保所有 worker 完成
	time.Sleep(5 * time.Second)
}

在此示例中,defer 确保每个 worker goroutine 在退出时打印 "done" 信息。

总结

  • 基于 channel 的退出模式 :通过共享的 channel 发送退出信号,其他 goroutine 监听该信号并退出。
  • 基于 context 的退出模式 :使用 context 管理 goroutine 的生命周期,支持超时和取消操作。
  • 基于超时的退出模式 :使用 context.WithTimeout 设置超时时间,超时后自动取消上下文,适用于需要在一定时间内完成任务的场景。
  • 基于 sync.WaitGroup 的退出模式 :使用 sync.WaitGroup 等待一组 goroutine 执行完毕,确保所有 goroutine 完成后再退出主程序。
  • 基于 defer 的退出模式 :在 goroutine 中使用 defer 语句来确保在退出时执行清理操作。
posted @ 2025-03-03 12:26  搁浅~浅浅浅  阅读(50)  评论(0)    收藏  举报