接上篇的初步思路,
可以通过这样的方式获取所有的需要匹配的订阅主题
接下来实现一波
// 获取需要匹配的主题,简单方式,没有考虑性能了,怎么简单怎么来
// 下面可优化的地方太多了,性能不是很好
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")
}
}
可见优化了挺多的
如有错误,请大声说我,欢迎好的想法分享。