大家知道Select 是 Go 中的一个控制结构,每个 case 必须是一个通信操作,要么是发送要么是接收操作。 select是 随机执行一个可运行的 case。
如果没有 case 可运行,程序可能会阻塞,直到有 case 可运行。当然有一个默认的子句(default子句)在没有任何条件满足的时候总是可运行的。
对于处理资源密集型的应用程序,超时处理是不可避免的。检查超时是有必要的,以确保超时运行的任务不会消耗应用程序的其他服务组件可能需要的资源或网络带宽。
Golang处理超时的方法非常简单。不需要复杂的代码,我们可以用channel通信和使用select语句作出超时决策来处理超时的问题。
在Go中,Select主要是和channel有关,其大概的格式如下:
Go的select与channel配合使用进行超时处理。channel必须是有缓冲channel,不然就是同步操作了。
select用于等待一个或者多个channel的输出。
应用场景
主goroutine等待子goroutine完成,但是子goroutine无限运行,导致主goroutine会一直等待下去(注意main也是一个携程)。而主线程想超过了一定的时间如果没有返回的话,
这时候可以进行超时判断然后继续运行下去。
我再举个开发中经常用到的例子,比如模拟网络连接,我们从一个模拟get请求的服务中读取响应。
如下面我编写一个简单结构体来接收服务的响应内容(这个例子没有考虑超时问题,稍后我后面说明补上)。
这里我直截了当地写了一个快速方法来获取服务中的响应,并返回给客户端,完整代码如下:
这是非常简单的方法。只是使用Golang原生http库读取http调用中的信息,并将响应内容存放在结构体中,在不同的步骤中处理错误。非常简单!
结果输出了一个来自模拟服务的虚拟响应信息如下(未超时):
现在来看请求正常,假设连接需要很长时间才能从服务器中获得响应,那么main函数将等待不确定时间了。
在实际应用程序中,这是没法接受的,因为这会消耗很多资源。要解决这个问题,我们在GetHttpResult函数中添加一个context参数。
这个context可以告我们何时停止尝试从网络中获取的结果。为了验证这一点,先编写一个帮助函数,执行和前面相同的操作,返回结果并将结果写入channel,
并使用一个独立的goroutine来执行实际的工作。为了简单起见,可以将响应和错误包装在一个CallResult结构体中,完整代码如下:
运行上面代码可以得到和之前相同的响应信息(注释掉time.Sleep)正常输出:
函数结束返回resChan。然后在单独的goroutine中执行网络连接,并将结果写入channel。这样代码实现非阻塞。
可以看到GetHttpResult函数现在变的更简单了,因为它必须做一个简单的选择。要么从通道中读取响应要么超时退出。
上面实现超时策略是通过select语句来完成的。以下是Done函数的定义:
Done返回一个channel,当涉及的context被取消,channel就会关闭。当context中有超时,就会在超时的时候对通道进行写操作。
在这种情况下,代码返回一个表示超时的错误响应信息。
另一个case是,helper函数能够在超时之前完成服务的响应读取,并写入channel。在这种情况下,在respChan变量中得到结果并返回给客户端。
上面main函数中调用GetHttpResult并传入一个1秒超时的context参数。再将超时减少到1毫秒(
),因为1毫秒内不足以完成网络调用。因此不会过多占用任何资源,而且只要context超时,就向客户端返回错误,而不是一直等待响应了。
Original: https://www.cnblogs.com/phpper/p/16449764.html
Author: 周伯通之草堂
Title: golang的超时处理使用技巧
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/578379/
转载文章受原作者版权保护。转载请注明原作者出处!