select+chan控制goroutine结束

1 一旦向chan中写入值了,select就执行之前阻塞的该通道,执行完后,再执行return,结束goroutine,

func main() {
    stop := make(chan bool)

    go func() {
        for {
            select {
            case <-stop:
                fmt.Println("监控退出,停止了...")
                return
            default:
                fmt.Println("goroutine监控中...")
                time.Sleep(2 * time.Second)
            }
        }
    }()

    time.Sleep(10 * time.Second)
    fmt.Println("可以了,通知监控停止")
    stop<- true
    //为了检测监控过是否停止,如果没有监控输出,就表示停止了
    time.Sleep(5 * time.Second)

}
View Code

注意select执行的时候是单线程,即如果只有case,要等每个case后的chan运行完,它才会去判断要执行那个case,所以尽量不要以自定义函数的形式返回chan,

package main
import (
    "context"
    "fmt"
    "sync"
    "time"
)
var res = make(map[string]string)
var rw sync.RWMutex
func writeMap(key string) (chan int){
    rw.Lock()
    res[key] = (key + " 网站爬虫结果")
    rw.Unlock()
    c := make(chan int, 1)
    c <- 0
    time.Sleep(time.Second * 10)
    return c
}
func doSomething(ctx context.Context, key string) {
    select {
    case <-ctx.Done():
        fmt.Println(key + "超时了,爬取未完成")
    case <- writeMap(key):
        fmt.Println(key + "网站爬取完成")
    }
}
func main() {
    var url = []string{
        "www.baidu.com",
        "www.123.com",
        "www.456.com",
    }
    for _, num := range url {
        //ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*5)
        ctx, _ := context.WithTimeout(context.Background(), time.Second * 1)
        //defer cancel()
      go doSomething(ctx, num)
    }
    time.Sleep(time.Second * 5)
    fmt.Println(res)
}
View Code

通过下面这个程序可以更清晰的看出来,

func test()(chan int){
    time.Sleep(time.Second * 5)
    res := make(chan int, 1)
    res <- 1
    return res
}
func main(){
    c := make(chan int, 1)
    c <- 1
    select {
    case <- c:
        fmt.Println("停顿5秒后才输出:aaa")
    case <- test():
        fmt.Println("bbb")
    }
}
View Code

ttt

原文地址:https://www.cnblogs.com/xxswkl/p/14219706.html