Golang:MQTT服务集群共享主题设计【通配符实现篇】

4 篇文章 0 订阅

接上篇的初步思路
在这里插入图片描述
可以通过这样的方式获取所有的需要匹配的订阅主题
在这里插入图片描述

接下来实现一波

// 获取需要匹配的主题,简单方式,没有考虑性能了,怎么简单怎么来
// 下面可优化的地方太多了,性能不是很好
func matchTopicS(topic string) []string {
	tp := strings.Split(topic, "/")
	ret := list.New()
	ret.PushBack(tp[0])
	// 直接限制订阅主题第一个不能是通配符,并且不能是单纯一个/,所以该方法就不做限制
	for k := range tp {
		if k == 0 {
			continue
		}
		v := tp[k]
		size := ret.Len()
		for i := 0; i < size; i++ {
			el := ret.Front()
			s := el.Value.(string)
			if s != "" && s[len(s)-1] == '#' {
				ret.MoveToBack(el)
				continue
			}
			el.Value = s + "/" + v
			ret.MoveToBack(el)
			ret.PushBack(s + "/+")
			ret.PushBack(s + "/#")
		}
	}

	da := make([]string, 0)
	for elem := ret.Front(); elem != nil; elem = elem.Next() {
		vs := elem.Value.(string)
		if vs == "" {
			continue
		}
		da = append(da, vs)
	}
	return da
}

性能测试一下

func BenchmarkShare(b *testing.B) {
	for i := 0; i < b.N; i++ {
		matchTopicS("/asdsds/aasdddsaa/aasadas/")
	}
}
goos: windows
goarch: amd64
pkg: Go-MQTT/redis/redis_test
BenchmarkShare-4          145756              7503 ns/op            4240 B/op        127 allocs/op
PASS
ok      Go-MQTT/redis/redis_test        1.650s

效果不是特别理想,但是能达到效果

func TestShare(t *testing.T) {
	fmt.Println(matchTopicS("/as/aa/aa"))
	fmt.Println(matchTopicS("/as/aa"))
	fmt.Println(matchTopicS("as/aa/"))
	fmt.Println(matchTopicS("/"))
	fmt.Println(matchTopicS(""))
}
[/as/aa/aa /as/aa/+ /as/aa/# /as/+/aa /as/+/+ /as/+/# /as/# /+/aa/aa /+/aa/+ /+/aa/# /+/+/aa /+/+/+ /+/+/# /+/# /#]
[/as/aa /as/+ /as/# /+/aa /+/+ /+/# /#]
[as/aa/ as/aa/+ as/aa/# as/+/ as/+/+ as/+/# as/#]
[/ /+ /#]
[]

这个时候就该去改动一下redis lua脚本了,详细请前往仓库看,可以部署我的代码运行体验

优化搜索

func MatchTopicSV2(topic string) []string {
	if len(topic) == 1 && (topic == "/" || topic == "#") {
		return nil
	}
	tp := strings.Split(topic, "/")
	size := strings.Count(topic, "/")
	ret := make([]string, 0, 1<<(size+1)-1)
	for i := 0; i < 3; i++ {
		dfs(tp, i, 1, tp[0], &ret)
	}
	return ret
}
func dfs(tps []string, index, level int, tempTp string, ret *[]string) {
	if index == 0 {
		*ret = append(*ret, tempTp+"/#")
		return
	} else if index == 1 {
		tempTp = tempTp + "/+"
	} else {
		tempTp = tempTp + "/" + tps[level]
	}
	level++
	if level == len(tps) {
		*ret = append(*ret, tempTp)
		return
	}
	for i := 0; i < 3; i++ {
		dfs(tps, i, level, tempTp, ret)
	}
}

上面两个性能测试一下

func BenchmarkShare(b *testing.B) {
	for i := 0; i < b.N; i++ {
		matchTopicS("/a/b/c/d/e")
	}
}
func BenchmarkShare2(b *testing.B) {
	for i := 0; i < b.N; i++ {
		matchTopicSV2("/a/b/c/d/e")
	}
}

在这里插入图片描述
可见优化了挺多的

如有错误,请大声说我,欢迎好的想法分享。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值