超时处理

超时 对于一个连接外部资源,或者其它一些需要花费执行时间的操作的程序而言是很重要的。

得益于通道和 select,在 Go中实现超时操作是简洁而优雅的。

import (
"fmt"
"time"
) // 例子中,假如我们执行一个外部调用,并在 2 秒后通过通道 c1 返回它的执行结果。
func main() { c1 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c1 <- "result 1"
}() // 这里是使用 select 实现一个超时操作。
// res := <- c1 等待结果,<-Time.After 等待超时时间 1 秒后发送的值。
// 由于 select 默认处理第一个已准备好的接收操作,如果这个操作超过了允许的 1 秒的话,将会执行超时 case。
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("timeout 1")
} // 如果我允许一个长一点的超时时间 3 秒,将会成功的从 c2接收到值,并且打印出结果。
c2 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(time.Second * 3):
fmt.Println("timeout 2")
}
}

输出

timeout 1
result 2

运行这个程序,首先显示运行超时的操作,然后是成功接收的。

使用这个 select 超时方式,需要使用通道传递结果。

非阻塞通道操作

常规的通过通道发送和接收数据是阻塞的。

然而,我们可以使用带一个 default 子句的 select 来实现非阻塞 的发送、接收,甚至是非阻塞的多路 select。

func main() {
messages := make(chan string)
signals := make(chan bool) // 这里是一个非阻塞接收的例子。如
// 果在 messages 中存在,然后 select 将这个值带入 <-messages case中。
// 如果不是,就直接到 default 分支中。
select {
case msg := <-messages:
fmt.Println("received message ", msg)
default:
fmt.Println("no message received")
} // 一个非阻塞发送的实现方法和上面一样。
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message sent")
} // 我们可以在 default 前使用多个 case 子句来实现一个多路的非阻塞的选择器。
// 这里我们试图在 messages和 signals 上同时使用非阻塞的接受操作。
select {
case msg := <-messages:
fmt.Println("received message", msg)
case sig := <-signals:
fmt.Println("received signal", sig)
default:
fmt.Println("no activity")
}
}

输出

no message received
no message sent
no activity

通道的关闭

关闭 一个通道意味着不能再向这个通道发送值了。这个特性可以用来给这个通道的接收方传达工作已经完成的信息。

import (
"fmt"
"time"
) // 在这个例子中,我们将使用一个 jobs 通道来传递 main() 中 Go协程任务执行的结束信息到一个工作 Go 协程中。
// 当我们没有多余的任务给这个工作 Go 协程时,我们将 close 这个 jobs 通道。
func main() {
jobs := make(chan int, 5)
done := make(chan bool) // 这是工作 Go 协程。使用 j, more := <- jobs 循环的从jobs 接收数据。
// 在接收的这个特殊的二值形式的值中,如果 jobs 已经关闭了,并且通道中所有的值都已经接收完毕,那么 more 的值将是 false。
// 当我们完成所有的任务时,将使用这个特性通过 done 通道去进行通知。
go func() {
for {
j, more := <-jobs
if more {
fmt.Println("received job", j)
} else {
fmt.Println("received all jobs")
done <- true
return
}
}
}() // 这里使用 jobs 发送 3 个任务到工作函数中,然后关闭 jobs。
for j := 1; j <= 3; j++ {
jobs <- j
fmt.Println("sent job", j)
time.Sleep(100)
}
close(jobs)
fmt.Println("sent all jobs") // 我们使用前面学到的通道同步方法等待任务结束。
<-done
}

输出

sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs

如果去掉 time.Sleep(100) 这句

sent job 1
sent job 2
sent job 3
received job 1
received job 2
received job 3
sent all jobs
received all jobs

通道遍历

for 和 range为基本的数据结构提供了迭代的功能。我们也可以使用这个语法来遍历从通道中取得的值。

func main() {
// 我们将遍历在 queue 通道中的两个值。
queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue) // 这个 range 迭代从 queue 中得到的每个值。
// 因为我们在前面 close 了这个通道,这个迭代会在接收完 2 个值之后结束。
// 如果我们没有 close 它,我们将在这个循环中继续阻塞执行,等待接收第三个值
for elem := range queue {
fmt.Println(elem)
}
}

输出

one
two

一个非空的通道也是可以关闭的,但是通道中剩下的值仍然可以被接收到。

[Golang]-6 超时处理、非阻塞通道操作、通道的关闭和遍历的更多相关文章

  1. golang 中 channel 的非阻塞访问方法

    在golang中,基本的channel读写操作都是阻塞的,如果你想要非阻塞的,可以使用如下示例: 即只要在select中加入default,阻塞立即变成非阻塞: package main import ...

  2. 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O

    Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...

  3. Linux IO模式-阻塞io、非阻塞io、多路复用io

    一 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进程的阻塞 - 文件描述符 - 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对3 ...

  4. TCP之非阻塞connect和accept

    套接字的默认状态是阻塞的,这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待响应操作完成,可能阻塞的套接字调用可分为以下四类: (1) 输入操作,包括read,readv,rec ...

  5. Nonblocking Memory Refresh&2018ISCA/Security& 非阻塞内存刷新

    Abstract 我们提议的非阻塞刷新工作是一次刷新内存块中的一部分数据,并在内存块中使用冗余数据,如RS码,在块中计算块的刷新/不可读数据以满足读取请求.作为概念的证明,我们将非阻塞刷新应用于服务器 ...

  6. UNP学习 非阻塞I/O

    缺省状态下,套接口时阻塞方式的.这意味着当一个套接口调用不能立即完成时,进程进入睡眠状态,等待操作完成.我们将可能阻塞的套接口调用分成四种. 1.输入操作:read.readv.recv.recvfr ...

  7. 理解Twisted与非阻塞编程

    先来看一段代码: # ~*~ Twisted - A Python tale ~*~ from time import sleep # Hello, I'm a developer and I mai ...

  8. EAGAIN、EWOULDBLOCK、EINTR与非阻塞 长连接

    EAGAIN.EWOULDBLOCK.EINTR与非阻塞 长连接 EWOULDBLOCK用于非阻塞模式,不需要重新读或者写 EINTR指操作被中断唤醒,需要重新读/写 在Linux环境下开发经常会碰到 ...

  9. ffmpeg中关于EAGAIN的理解及非阻塞IO

    ffmpeg为在linux下开发的开源音视频框架,所以经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中).  try again,从字面上来看,是提 ...

随机推荐

  1. 目前用下来最溜的MacOS微信多开工具!

    一个生活微信,一个工作微信是很多上班族的基本配置. 但由于微信客户端在PC端上只能打开一个,这使得在上班时候就非常不便,一个号在PC端上登录,一个在手机上使用,但是上班时候又不能一直看手机,不然老板还 ...

  2. Redis 实战 —— 07. 复制、处理故障、事务及性能优化

    复制简介 P61 关系型数据库通常会使用一个主服务器 (master) 向多个从服务器 (slave) 发送更新,并使用从服务器来处理所有读请求. Redis 也采用了同样的方法实现自己的复制特性,并 ...

  3. Python攻城——查看,生成幫助文檔

    1. python在控制台中查看文檔 1 python -m pydoc 模塊名 2. pydoc生成HTML文檔 1 python -m pydoc -w 模塊名 1 python -m pydoc ...

  4. MySQL调优之分区表

    一.分区表的应用场景 1.为什么是用分区表? 表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据,分区表是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理 ...

  5. Lucene 查询原理 传统二级索引方案 倒排链合并 倒排索引 跳表 位图

    提问: 1.倒排索引与传统数据库的索引相比优势? 2.在lucene中如果想做范围查找,根据上面的FST模型可以看出来,需要遍历FST找到包含这个range的一个点然后进入对应的倒排链,然后进行求并集 ...

  6. Spring框架入门浅析

    一.Spring Bean的配置 在需要被Spring框架创建对象的实体类的类声明前面加注解:```@component```.这样在Spring扫描的时候,看到该注解就会在容器中创建该实体类的对象. ...

  7. 深入理解SPI机制-服务发现机制

    https://www.jianshu.com/p/3a3edbcd8f24 SPI ,全称为 Service Provider Interface,是一种服务发现机制.它通过在ClassPath路径 ...

  8. RMI笔记

    这是<java核心技术> 第11章 分布式对象的笔记. RMI基本原理 我们使用远程方法调用是希望达到这样的目的: 可以像调用本地方法一样去调用一个远程方法. 实现远程调用的方式是 为客户 ...

  9. tarjan复习笔记 双连通分量,强连通分量

    声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...

  10. CF1190B

    扯在前面 我们老师刚讲过的题目,很考验思维,本蒟蒻WA了十发才过,然后看到题解里只是指出了特殊情况没多解释,可能有人看不懂,特来分享一下 首先题目就很有意思,思考的过程也很有趣,想把所有情况思考全思考 ...