go并发模式二:任务的控制

九路 等级 47 0 0
标签:

任务的控制

任务的控制,主要涉及到以下几个方面

  • 非阻塞等待
  • 超时机制
  • 任务中断/退出
  • 优雅退出

1 非阻塞等待

// 非阻塞等待, 收到数据,返回数据,以及true , 收不到数据,返回"", false
func nonBlockWait(c chan string) (string, bool) {
    select {

    //如果没有收到值,会阻塞在此
    case m := <-c:
        return m, true

    //上面的case是阻塞的,收不到值就会等待,但是加了default,就变成非阻塞了
    //因为上面的case如果收不到值,就会走到default,所以加了一个default就变成了非阻塞了
    default:
        return "", false
    }
} 

用法如下:

func main() {
    c1 := messageGen("service1")
    c2 := messageGen("service2")

    for {
        fmt.Println(<-c1)
        if m, ok := nonBlockWait(c2); ok {
            fmt.Println(m)
        } else {
            fmt.Println("no message from service2")
        }
    }
}

2 超时机制

// 超时机制
func timeoutWait(c <-chan string, timeout time.Duration) (string, bool) {
    select {
    case val := <-c:
        return val, true
    case <-time.After(timeout):
        return "", false
    }
}

用法如下:

func main() {
    c2 := messageGen("service2")

    for {
        if m, ok := timeoutWait(c2, 2*time.Second); ok {
            fmt.Println(m)
        } else {
            fmt.Println("no message from service2")
        }
    }
}

退出机制

func msgGen(name string, done chan struct{}) chan string {
    c := make(chan string)
    go func() {
        i := 0
        for {
            select {
            case <-time.After(time.Duration(rand.Intn(5000)) * time.Microsecond):
                c <- fmt.Sprintf("service %s: message %d", name, i)
            case <-done: //收到外面的值了,表明要退出了
                fmt.Println("cleaning up")
                return
            }
            i++
        }
    }()
    return c
}

func main() {
    done := make(chan struct{})
    c := msgGen("service1", done)
    for i := 0; i < 10; i++ {
        if m, ok := timeoutWait(c, 2*time.Second); ok {
            fmt.Println(m)
        } else {
            fmt.Println("no message from service2")
        }
    }
    done <- struct{}{} //主动退出

    time.Sleep(6 * time.Second)
}

优雅退出

func msgGen(name string, done chan struct{}) chan string {
    c := make(chan string)
    go func() {
        i := 0
        for {
            select {
            case <-time.After(time.Duration(rand.Intn(5000)) * time.Microsecond):
                c <- fmt.Sprintf("service %s: message %d", name, i)
            case <-done: //收到外面的值了,表明要退出了
                fmt.Println("cleaning up")
                //清理工作可能要做10分钟
                time.Sleep(10 * time.Minute)

                // 清理完工作做完后,要退出,此时可以把done这个chan做成一个双向的
                // 清理工作完成后,再向done发一个数据
                done <- struct{}{} //清理工作做过多了,发一个数据,告诉外面,要退出了,
                // 此时外面如果接收了,就往下走了,return了,退出了,如果外面没有接收,此行代码会阻塞,直到外面接收
                return
            }
            i++
        }
    }()
    return c
}

func main() {
    done := make(chan struct{})
    c := msgGen("service1", done)
    for i := 0; i < 10; i++ {
        if m, ok := timeoutWait(c, 2*time.Second); ok {
            fmt.Println(m)
        } else {
            fmt.Println("no message from service2")
        }
    }
    done <- struct{}{} //主动退出

    <-done //接收来自子任务是否真的完成,收到数据说明完成了,main函数走完了,就退出了
}
收藏
评论区

相关推荐

Golang中常用的字符串操作
Golang中常用的字符串操作 一、标准库相关的Package go import( "strings" ) 二、常用字符串操作 1. 判断是否为空字符串 1.1 使用“”进行判断 思路:直接判断是否等于""空字符串,由于Golang中字符串不能为 nil,且为值类型,所以直接与空字符串比较即可。 举例: go
部署Go语言项目的 N 种方法
本文以部署 Go Web 程序为例,介绍了在 CentOS7 服务器上部署 Go 语言程序的若干方法。独立部署Go 语言支持跨平台交叉编译,也就是说我们可以在 Windows 或 Mac 平台下编写代码,并且将代码编译成能够在 Linux amd64 服务器上运行的程序。对于简单的项目,通常我们只需要将编译后的二进制文件拷贝到服务器上,然后设置为后台
一篇文章带你弄懂Python异常简介和案例分析
点击上方“Go语言进阶学习”,进行关注回复“Go语言”即可获赠从入门到进阶共10本电子书今日鸡汤似此星辰非昨夜,为谁风露立中宵。大家好,我是Go进阶者,今天给大家分享一些Python基础 (异常),一起来看看吧一、异常简介当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常"。 二、案例分析 打开一个不存在的
(Go)04.go工作区目录规范及简单例子
一.规范目录结构 -------- D:\\project\\src\\go\_dev\\day1\\example1 ![](https://img2018.cnblogs.com/blog/683937/201901/683937-20190124112023185-189177204.png) 二.设置GOPAH环境变量 ------------
Go文档支持
Go文档查看帮助很方便,主要可以通过以下两种方式查看 第一种,Go本地运行(参考:#Go语言安装#)起来后,References下面: * Package Go标准函数库说明。 * Command Go工具说明。 * Language Specification Go官
go——并发(二)
通常程序会被编写为一个顺序执行并完成一个独立任务的代码。 如果没有特别的需求,最好总是这样写代码,因为这种类型的程序通常很容易写,也容易维护。 不过也有一些情况下,并行执行多个任务会有更大的好处。 一个例子是,Web服务需要在各自独立的套接字上同时接收多个数据请求。 每个套接字请求都是独立的,可以完全独立于其它套接字进行处理。 具有并行执行多个请求
go语言入门
一安装go go下载地址 [https://golang.org/doc/install](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgolang.org%2Fdoc%2Finstall) 二 开发工具 liteIDE 参考[https://www.kafan.cn/edu/51
Archlinux下Visual Studio Code配置Golang开发环境
一、Golang的安装 ----------- GoLang安装并验证一下: [cox@localhost ~]$ sudo pacman -S go [cox@localhost ~]$ go version go version go1.8.3 linux/amd64s 要注意,Golang的安装要确保两个环境变量,一个是G
GO开发[二]:golang语言基础
一.变量 ==== 1.声明变量 ------ 变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间。 Go语言引入了关键字var,而类型信息放在变量名之后,变量声明语句不需要使用分号作为结束符,示例如下: var v1 int var v2 string
Go实现FastCgi Proxy Client 系列(四) keep
先贴几个链接 ====== 前三篇 [Go实现FastCgi Proxy Client 系列(三)](https://my.oschina.net/lwl1989/blog/1813102) [Go实现FastCgi Proxy Client 系列(二)](https://my.oschina.net/lwl1989/blog/1789583) [G
Hyperledger Fabric v1.1.0环境搭建
### 一、搭建基础环境 参考:https://www.cnblogs.com/sky-cheng/p/12150822.html ### 二、下载Hyperledger Fabric 源代码 查看$GOPATH环境变量 [root@localhost home]# echo $GOPATH /home/go 新建如下目录
Python 关于super 的 用法和原理(挖坑)
一、前言 Python 面向对象中有继承这个概念,初学时感觉很牛逼,里面也有个super类,经常见到,最近做一些题才算是理解了。特地记录分享给后来研究的小伙伴,毕竟现在小学生都开始学了(滑稽脸) 二、代码 直接上干货,能把下面一个问题全答对,后面就不用看了。 class A(): def go(self):
Python 协程与 Go 协程的区别(二)
👆 “Python猫” ,一个值得加星标的公众号 **花下猫语:** 今天继续分享协程系列的第二篇。万字长文,收藏起来慢慢读吧。PS:原文中有挺多参考链接,微信不能很好保留。故建议阅读原文。 作者:lgj\_bky(经作者授权转载) 原文: https://www.cnblogs.com/lgjbky/p/10838035.html 写在前面
Sentinel-Go 源码系列(一)|开篇
大家好呀,打算写一个 Go 语言组件源码分析系列,一是为了能学习下 Go 语言,看下别人是怎么写 Go 的,二是也掌握一个组件。本次选择了 SentinelGo,一是对 Java 版本的 Sentinel 算是有一些了解,也在生产上落地过,二是感觉他的代码应该不会太复杂(仅仅是感觉),三是在云原生越来越热的趋势下,用 Go 实现的限流降级容错应该是比较通用的