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

九路
• 阅读 192

任务的控制

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

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

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
1年前
JAVA中的BIO、NIO和AIO
Java中的IO方式主要分为3种:BIO(同步阻塞)、NIO(同步非阻塞)和AIO(异步非阻塞)。BIO同步阻塞模式。在JDK1.4以前,使用Java建立网络连接时,只能采用BIO方式,在服务器端启动一个ServerSocket,然后使用accept等待客户端请求,对于每一个请求,使用一个线程来进行处理用户请求。线程的大部分时间都在等待请求的
Wesley13 Wesley13
1年前
BIO、NIO、AIO 介绍和适用场景分析
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。一、同步阻塞的BIO在JDK1.4之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个serverSocket,然后在客户端启动socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否
Stella981 Stella981
1年前
Linux网络IO模型
同步和异步,阻塞和非阻塞_同步和异步_关注的是结果消息的通信机制同步:同步的意思就是调用方需要主动等待结果的返回异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等。_阻塞和非阻塞_主要关注的是等待结果返回调用方的状态阻塞:是指
Wesley13 Wesley13
1年前
Java多线程之线程安全队列Queue
在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。注:什么叫线程安全?这个首先要明确。
Wesley13 Wesley13
1年前
java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?
首先,服务器的实现不止有这两种方式。先谈谈题主说的这两种服务器模型:1、收到一个请求就处理,这个时候就不能处理新的请求,这种为阻塞这个是单线程模型,无法并发,一个请求没处理完服务器就会阻塞,不会处理下一个请求。一般的服务器不会使用这种方式实现。2、收到一个请求就新开一个线程去处理任务,主线程返回,继续处理下一个任务,这种为非阻塞首先纠
Stella981 Stella981
1年前
Netty学习之IO模型
目录1.1同步、异步、阻塞、非阻塞  同步VS异步    同步    异步  阻塞VS非阻塞    阻塞    非阻塞  举例    1)同步阻塞    2)同步非阻塞    3)异步阻塞    4)异步非阻塞1.2Li
Wesley13 Wesley13
1年前
JAVA线程15
一、阻塞队列1\.概述阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue。阻塞队列是一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元
Stella981 Stella981
1年前
Python异步Web编程
!(https://oscimg.oschina.net/oscnet/c170345b07b2bf0b8c076ee4350fe145ad0.jpg)异步编程适用于那些频繁读写文件和频繁与服务器交互数据的任务,异步程序以非阻塞的方式执行I/O操作。这样意味着程序可以在等待客户机返回数据的同时执行其他任务,而不是无所事事的等待,浪费资源和时间。
Wesley13 Wesley13
1年前
NIO
一、什么是阻塞和非阻塞?传统的IO流都是阻塞式的。也就是说,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行IO操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端
Stella981 Stella981
1年前
Redis常用操作
1.BLPOPkey\key...\timeoutBLPOP 是列表的阻塞式(blocking)弹出原语。它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非