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

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

换句话说select后的case要就绪后才随机选一个,如果没有就绪就会先运行完,看看是不是阻塞、能不能写入或读出数据,如果都不能且没有defalut,就阻塞等待,否则执行default,

package main

import (
    "fmt"
    "time"
)

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")
    default:
        fmt.Println("不会直接走default")
    }
}
View Code

 

利用cancel和定时器控制协程结束

https://blog.csdn.net/weixin_44879611/article/details/115537192?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_paycolumn_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_paycolumn_v2&utm_relevant_index=1

posted on 2021-01-01 11:42  吃我一枪  阅读(213)  评论(0编辑  收藏  举报

导航