设想这样的场景,有很多人订阅某种数据。当用户订阅成功后我们需要按功能批量推送给用户。假设用户有3人:greece,lodon,egypt订阅了某个功能的数据,一旦这个功能的数据有新数据到达,我们需要一次性将这些数据推送给订阅的用户
我们想到最简单的方法就是定义一个map,key用来存放用户指针, value随便存放一个数,假设bool类型
先建一个用户类型:
type User struct {
connect int64
Name string
}
然后再建一个根据用户名创建用户的函数:
func MakeUser(name string) *User {
u := new(User)
u.Name = "greece"
return u
}
现在我们开始创始化一个用户集:这个用户集最后返回一个sync.Map
func InitUsers() sync.Map {
var scene sync.Map
u1 := MakeUser("greece")
u2 := MakeUser("london")
u3 := MakeUser("egypt")
scene.Store(u1, true)
scene.Store(u2, true)
scene.Store(u3, true)
return scene
}
顺带说一下,如果需要删除:
scene.Delete(u1)
可以线程安全地完成删除工作。
由于订阅和推送在不同的线程中,我们利用了go自带的多线程的map进行。这里最主要的是要实现把map中的key一次性取出,然后推送出去的功能。
sync.Map中遍历需要使用匿名函数
scene.Range(func(k, v interface{}) bool {
number, _ := k.(*User)
fmt.Println(number.Name)
return true
})
可以打印出每个用户的指针。
我们不能在回调中进行数据的发送,因此需要通过一个缓存,将指针放入此缓存中,供推送函数使用
var users []*User
scene.Range(func(k, v interface{}) bool {
number, _ := k.(*User)
users = append(users, number)
return true
})
fmt.Println("从sync.Map中取出的元素...")
for _, value := range users {
fmt.Println(value.Name)
}
当我们取出了map中的指针时,就可以一次性将分时数据推送给用户了。
有同学会说,我可能在别的线程中删除了指针,引发空指针的问题,这个不用担心,如果你在其它线程中先一步删除了某个指针,则遍历时不会得到对应的元素,若你在遍历后删除了某个指针,此时这个指针存在users数组中,不会空挂,根据go语言特性,只要有变量在使用,指针就不会被删除。
附全部代码:
// 测试 sync.map
package test
import (
"fmt"
"sync"
"testing"
)
type User struct {
connect int64
Name string
}
func MakeUser(name string) *User {
u := new(User)
u.Name = "greece"
return u
}
func InitUsers() sync.Map {
var scene sync.Map
u1 := MakeUser("greece")
u2 := MakeUser("london")
u3 := MakeUser("egypt")
scene.Store(u1, true)
scene.Store(u2, true)
scene.Store(u3, true)
return scene
}
func TestSyncMap(t *testing.T) {
scene := InitUsers()
var users []*User
scene.Range(func(k, v interface{}) bool {
number, _ := k.(*User)
users = append(users, number)
return true
})
fmt.Println("从sync.Map中取出的元素...")
for _, value := range users {
fmt.Println(value.Name)
}
}