go语言-用channel控制goroutine的退出

用channel控制goroutine的退出

本文简要介绍了,如何用channel控制goroutine的退出的基本方法

for-range主动停止goruitine

复制代码
package main

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

/*
Go并发编程模型:主动停止goroutine
方法一:for-rang从channel上接收值,直到channel关闭
*/
var wg sync.WaitGroup

func work(ch chan int) {
	defer wg.Done()
	// for range关键字,将其使用在channel上时,会自动等待channel的动作一直到channel被关闭close
	// 也就是clase(sh)后,for range就会退出
	for i := range ch {
		fmt.Println(i)
	}
	fmt.Println("work exit")
}

func main() {

	wg.Add(1)
	var ch chan int
	ch = make(chan int)

	go work(ch)

	for i := 0; i < 3; i++ {
		time.Sleep(1 * time.Second)
		ch <- i
	}

	time.Sleep(3 * time.Second)
	for i := 4; i < 7; i++ {
		time.Sleep(1 * time.Second)
		ch <- i
	}

	// close(sh)来控制"work"协程中的for range的完成
	close(ch)
	wg.Wait()
}

后台定时任务

复制代码
	// 设定一个定时器,当定时器触发是就执行一次任务
	tricker := time.NewTicker(1 * time.Second)
	defer fmt.Println("tricker.Stop()")
	defer tricker.Stop()

	for {
		select {
		case <-stopCh:
			fmt.Println("do1 exit.")
			return
		//心跳,心跳一次就执行一次任务
		case <-tricker.C:
			time.Sleep(1 * time.Second)
			fmt.Println("do1 doing....")
		}
	}

使用stopCh控制goroutine退出

复制代码
package main

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

var wg sync.WaitGroup

func do1(stopCh chan struct{}) {
	defer wg.Done()
	for {
		select {
		case <-stopCh:
			fmt.Println("go1 exit.")
			return
		default:
			time.Sleep(1 * time.Second)
			fmt.Println("go1 doing....")
		}
	}
}
func do2(stopCh chan struct{}) {
	defer wg.Done()
	for {
		select {
		case <-stopCh:
			fmt.Println("go2 exit.")
			return
		default:
			time.Sleep(1 * time.Second)
			fmt.Println("go2 doing....")
		}
	}
}

func main() {

	wg.Add(2)
	stopCh := make(chan struct{})
	go do1(stopCh)
	go do2(stopCh)

	time.Sleep(5 * time.Second)

	// 让一个goroutine退出
	stopCh <- struct{}{}

	time.Sleep(5 * time.Second)

	// 让另一个goroutine退出
	stopCh <- struct{}{}

	wg.Wait()

}

关闭channel来控制goroutine退出

复制代码
package main

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

/*
多个通道都关闭才退出
利用select的一个特性,select不会在nil的通道上进行等待
*/
var wg sync.WaitGroup

func work(in, exit1, exit2 chan bool) {
	defer wg.Done()

	for {
		select {
		// 当exit管道收到信号后退出goroutine
		case v := <-exit1:
			fmt.Println("exit1 收到退出信号")
			fmt.Println("v=", v)
			exit1 = nil

		case <-exit2:
			fmt.Println("exit2 收到退出信号")
			exit2 = nil

		case value := <-in:
			fmt.Println(value)
		}
		fmt.Println(time.Now())
		fmt.Println("遍历了一次")

		// 当2个退出通道都收到信号时,就退出for循环
		if exit1 == nil && exit2 == nil {
			return
		}
	}

}

func main() {

	in := make(chan bool)
	exit1 := make(chan bool)
	exit2 := make(chan bool)

	wg.Add(1)
	go work(in, exit1, exit2)

	for i := 0; i < 6; i++ {
		time.Sleep(5 * time.Millisecond)
		in <- true
	}

	// 主动停止goroutine方法一
	//exit1 <- 1
	//exit2 <- 1

	// 主动停止goroutine方法二
	close(exit1)
	close(exit2)

	wg.Wait()

}
相关推荐
38242782715 分钟前
python3网络爬虫开发实战 第二版:绑定回调
开发语言·数据库·python
星月心城20 分钟前
面试八股文-JavaScript(第五天)
开发语言·javascript·ecmascript
wjs202424 分钟前
PostgreSQL 时间/日期处理指南
开发语言
wniuniu_27 分钟前
ceph的参数
java·数据库·ceph
wniuniu_30 分钟前
ceph心跳机制
开发语言·ceph·php
阿里嘎多学长34 分钟前
2025-12-25 GitHub 热点项目精选
开发语言·程序员·github·代码托管
一只专注api接口开发的技术猿37 分钟前
智能决策数据源:利用 1688 商品详情 API 构建实时比价与供应链分析系统
大数据·前端·数据库
Oxye40 分钟前
服务器内存不足导致程序没完全起起来,报错Required type must not be null
java·开发语言
乾元42 分钟前
自动化补丁评估与策略回滚:网络设备固件 / 配置的风险管理
运维·开发语言·网络·人工智能·架构·自动化
2501_9167665443 分钟前
【Java】static关键字与类的加载顺序
java·开发语言