go语言心跳超时的实现示例

 更新时间:2022-05-13 14:12:27   作者:佚名   我要评论(0)

目录一、背景二、心跳超时的实现2.1 通过select case (设计概念比较多)2.2 通过time.sleep(简单有效)三、个人的实现观感一、背景
本文描

一、背景

本文描述的是客户端接收心跳信息的超时实现。心跳超时,或者接受信息超过限定时间在分布式系统中出现的次数比较多。常见的就有hadoop中节点超时,或者日志中出现timeout的字样。

在学习go语言中,我也根据go语言的机制实现了心跳超时的这个问题。踩过坑,趟过水。

二、心跳超时的实现

2.1 通过select case (设计概念比较多)

这种方法实现心跳,需要对go语言中的channel和select case 机制有所了解。select代码段中没有包含default条件时,会一直阻塞到有通道操作。

需要注意的是!!!! select语言只会阻塞一次,且执行一次。如果需要多次判断,或者可能有多个case条件需要满足,那就需要增加for语句。

首先需要知道的是select是专为channel设计的,所以说每个case表达式都必须是包含操作通道的表达式。下面这段代码是描述了随机抽取一个channel发消息,正常情况下,不会触发超时。为了触发超时,注释掉通道发送数据操作。超时五秒,则触发超时。

package main
 
import (
    "fmt"
    "math/rand"
    "time"
)
 
func main() {
    // 准备好三个通道。
    intChannels := [3]chan int{
        make(chan int, 1),
        make(chan int, 1),
        make(chan int, 1),
    }
    // 随机选择一个通道,并向它发送元素值。
    index := rand.Intn(3)
    fmt.Printf("The index: %d\n", index)
 
    //?? 取消这行代码的注视,超时条件的选择就会触发。
    //intChannels[index] <- index
    // 哪一个通道中有可取的元素值,哪个对应的分支就会被执行。
    select {
    case <-intChannels[0]:
        fmt.Println("The first candidate case is selected.")
    case <-intChannels[1]:
        fmt.Println("The second candidate case is selected.")
    case elem := <-intChannels[2]:
        fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)
    case <-time.After(5 * time.Second):
        fmt.Println("timed out")
    }
}

2.2 通过time.sleep(简单有效)

通过time.sleep()实现超时操作,是比较巧妙的。一般来说心跳超时是一个双方交互的行为。

下面画一个图来描述一下。

 为了方便理解,定义双方都使用共同时间。

下面是代码。

基本的逻辑是:

        1、先给客户端设置一个下次超时的时间

         2、客户端每次收到心跳的时候,更新这个时间

         3、开启一个独立的线程,一致判断当前客户端是否超时。

ps:结合时效和性能,可以间隔一定的时间来进行判断。

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
type Client struct {
    lock sync.Mutex //加锁
    nextTimeOutTime time.Time //下次超时时间
}
 
const tenSec = 10
/**
刷新每次的心跳超时机制
 */
func (client *Client) freshTimeOutTime()  {
    client.lock.Lock()
    defer client.lock.Unlock()
    client.nextTimeOutTime =time.Now().Add(tenSec*time.Second)
}
 
//开启一个gp,每隔500ms判断有没有超时
func (client *Client) judgeTimeOut()  {
    for  {
        time.Sleep(500*time.Millisecond)
        fmt.Printf("%v 在判断是否超时\n", client.nextTimeOutTime)
        if time.Now().After(client.nextTimeOutTime) {
            fmt.Printf("%v 超时了\n", client.nextTimeOutTime)
        }
    }
}
 
//客户端收到以后,修改下次心跳超时时间
func (client *Client) receiveHeart()  {
    client.freshTimeOutTime()
}
 
//开启一个模拟ping 客户端的线程
func pingClient(client *Client)  {
    for true {
        time.Sleep(11*time.Second)
        fmt.Printf("%v 请求发送时间\n", time.Now())
        client.receiveHeart()
    }
 
}
 
func main() {
    client := Client{
        lock:            sync.Mutex{},
        nextTimeOutTime: time.Time{},
    }
    //在当前时刻,更新下次的超时时刻是10s中后
    client.freshTimeOutTime()
 
 
    go pingClient(&client)
 
 
    go client.judgeTimeOut()
 
    for true {
 
    }
}

三、个人的实现观感

使用select case 和 time.sleep实现超时的最大区别在于,time.sleep没有太多的??语言相关的语法和知识,更容易理解和掌握。相对于channel来说,掌握需要了解channel的基本使用方法,一些常见的特性等。

到此这篇关于go语言心跳超时的实现示例的文章就介绍到这了,更多相关go语言心跳超时内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
  • go语言中http超时引发的事故解决
  • Go语言利用time.After实现超时控制的方法详解
  • Go语言如何并发超时处理详解

相关文章

  • go语言心跳超时的实现示例

    go语言心跳超时的实现示例

    目录一、背景二、心跳超时的实现2.1 通过select case (设计概念比较多)2.2 通过time.sleep(简单有效)三、个人的实现观感一、背景 本文描
    2022-05-13
  • Java实现跳跃表的示例详解

    Java实现跳跃表的示例详解

    跳表全称叫做跳跃表,简称跳表,是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序列表上面增加多级索引,
    2022-05-13
  • 利用Java编写一个属于自己的日历

    利用Java编写一个属于自己的日历

    目录问题提出一点提示源码分享问题提出 编写程序,输入年份,打印出该年的年历(12个月的),效果如下图所示。 一点提示 使用 Java 自带的
    2022-05-13
  • C#操作注册表的方法

    C#操作注册表的方法

    目录一、注册表操作简介注册表巢Registry静态类RegistryKey类二、注册表项的创建、打开、删除1、创建,CreateSubKey2、打开,OpenSubKey3、删
    2022-05-13
  • C#操作注册表的方法

    C#操作注册表的方法

    目录一、注册表操作简介注册表巢Registry静态类RegistryKey类二、注册表项的创建、打开、删除1、创建,CreateSubKey2、打开,OpenSubKey3、删
    2022-05-13
  • python?函数定位参数+关键字参数+inspect模块

    python?函数定位参数+关键字参数+inspect模块

    目录函数内省(function introspection)定位参数和仅限关键字参数inspect模板函数内省(function introspection) 除了__doc__属性, 函数对象还
    2022-05-13
  • Python?pluggy模块的用法示例演示

    Python?pluggy模块的用法示例演示

    目录1 pluggy 简介2 安装3 使用初体验4 详解解释5 HookspeckMarker装饰器支持传入一些特定的参数6 HookImplMarker装饰器也支持传入一些特定的
    2022-05-13
  • go语言中如何使用select的实现示例

    go语言中如何使用select的实现示例

    目录1.基本语法2.select语句的实际应用在golang语言中,select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作
    2022-05-13
  • python中列表添加的四种方法小结

    python中列表添加的四种方法小结

    目录列表的添加1)+ 添加2)append 追加3)extend 拉伸4)insert 插入在列表指定位置添加元素列表的添加 1)+ 添加 2)append 追加 一次只能
    2022-05-13
  • C#操作注册表之Registry类

    C#操作注册表之Registry类

    提供表示 Windows 注册表中的根项的 RegistryKey 对象,并提供访问项/值对的 static 方法。 继承层次结构 System.Object Microsoft.Win3
    2022-05-13

最新评论