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

九路
• 阅读 465

任务的控制

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

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

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函数走完了,就退出了
}
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?
首先,服务器的实现不止有这两种方式。先谈谈题主说的这两种服务器模型:1、收到一个请求就处理,这个时候就不能处理新的请求,这种为阻塞这个是单线程模型,无法并发,一个请求没处理完服务器就会阻塞,不会处理下一个请求。一般的服务器不会使用这种方式实现。2、收到一个请求就新开一个线程去处理任务,主线程返回,继续处理下一个任务,这种为非阻塞首先纠
Wesley13 Wesley13
3年前
IO模型(BIO,NIO,AIO)及其区别
BIO:同步阻塞IONIO:同步非阻塞IOAIO:异步非阻塞IO先弄清楚同步、异步,阻塞、非阻塞概念。io操作分为两部分,发起io请求,和io数据读写。阻塞、非阻塞主要是针对线程发起io请求后,是否立即返回来定义的,立即返回称为非阻塞io,否则称为阻塞io。同步、异步主要针对io数据读写来定义的,读写数据过程中不阻塞线程称为异步io
Wesley13 Wesley13
3年前
JAVA中的BIO、NIO和AIO
Java中的IO方式主要分为3种:BIO(同步阻塞)、NIO(同步非阻塞)和AIO(异步非阻塞)。BIO同步阻塞模式。在JDK1.4以前,使用Java建立网络连接时,只能采用BIO方式,在服务器端启动一个ServerSocket,然后使用accept等待客户端请求,对于每一个请求,使用一个线程来进行处理用户请求。线程的大部分时间都在等待请求的
Stella981 Stella981
3年前
Linux网络IO模型
同步和异步,阻塞和非阻塞_同步和异步_关注的是结果消息的通信机制同步:同步的意思就是调用方需要主动等待结果的返回异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等。_阻塞和非阻塞_主要关注的是等待结果返回调用方的状态阻塞:是指
Wesley13 Wesley13
3年前
NIO阻塞与非阻塞IO
一、使用NIO完成网络通信的三个核心1、通道(Channel):负责连接java.nio.channels.Channel接口|–SelectableChannel|–SocketChannel|–ServerChannel|–DatagramChannel|–Pipe.SinkChannel|–Pipe
Wesley13 Wesley13
3年前
NIO高并发基础
NIO高并发是jdk1.4出现的新的流.NIONewIO同步式非阻塞式IOBIOBlockingIO同步式阻塞式IOUDP/TCPAIOAsynchronousIO异步式非阻塞IOjdk1.8BIO的缺点1.会产生阻塞行为receive/accept/connect/r
Stella981 Stella981
3年前
Netty学习之IO模型
目录1.1同步、异步、阻塞、非阻塞  同步VS异步    同步    异步  阻塞VS非阻塞    阻塞    非阻塞  举例    1)同步阻塞    2)同步非阻塞    3)异步阻塞    4)异步非阻塞1.2Li
Wesley13 Wesley13
3年前
JAVA线程15
一、阻塞队列1\.概述阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue。阻塞队列是一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元
Stella981 Stella981
3年前
Python异步Web编程
!(https://oscimg.oschina.net/oscnet/c170345b07b2bf0b8c076ee4350fe145ad0.jpg)异步编程适用于那些频繁读写文件和频繁与服务器交互数据的任务,异步程序以非阻塞的方式执行I/O操作。这样意味着程序可以在等待客户机返回数据的同时执行其他任务,而不是无所事事的等待,浪费资源和时间。
Stella981 Stella981
3年前
Redis常用操作
1.BLPOPkey\key...\timeoutBLPOP 是列表的阻塞式(blocking)弹出原语。它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非