Dictionary 可以使用什么数据结构来支持外键约束
给定一些上下文,我正在使用gRPC在服务器上实现扇出(流),每次客户端连接时,我都会将流保存到映射中,当客户端断开连接时,我只是将其从映射中删除,这样我就可以仅使用“活动”客户端/连接更新映射 因此,初始地图如下所示:Dictionary 可以使用什么数据结构来支持外键约束,dictionary,go,data-structures,tree,big-o,Dictionary,Go,Data Structures,Tree,Big O,给定一些上下文,我正在使用gRPC在服务器上实现扇出(流),每次客户端连接时,我都会将流保存到映射中,当客户端断开连接时,我只是将其从映射中删除,这样我就可以仅使用“活动”客户端/连接更新映射 因此,初始地图如下所示: key value client1 stream client2 stream client3 stream 此实现的问题是,如果客户端多次连接,则只有最后一个客户端(使用相同的密钥id)将接收“广播”消息,因为映射将用连接客户端的最新消息覆盖现
key value
client1 stream
client2 stream
client3 stream
此实现的问题是,如果客户端多次连接,则只有最后一个客户端(使用相同的密钥id
)将接收“广播”消息,因为映射将用连接客户端的最新消息覆盖现有流,因此我需要使用唯一密钥或找到匹配的方法,联系客户和联系
我发现很容易切换地图,并将连接ID用作键,类似这样
conn_id client_id
conn1 client1
conn2 client2 \
conn3 client2 > 3 connections for client ID 2
conn4 client2 /
这可以工作并有助于向所有连接的客户端发送消息,但如果我想向特定的客户端发送消息,则会使事情变得更复杂,因为我需要对整个映射进行范围/遍历,以便将值与所需的客户端相匹配
为了解决这个问题,我使用client_id切换回了映射,但是没有使用流作为值,而是使用了一个切片列表
key value
client1 [stream, stream, stream]
client2 [stream]
client3 [stream, stream]
问题仍然存在,因为为了向所有客户端发送消息,仍然需要遍历/范围完整映射,以获取每个客户端的流并向每个客户端发送消息
因此,在不使用数据库的情况下,我们可以按照与数据库相关的最佳实践使用什么样的数据结构
主要希望找到与数据库行为类似的东西,可能有两个映射,一个保持所有连接,另一个保持每个客户端的状态或连接数,例如:
key value client_id # streams
conn1 client1 client1 1
conn2 client2 client2 3
conn3 client2
conn4 client2
但是,当连接
映射中没有来自该客户机的更多连接时,如何“自动”从客户机
映射中删除该客户机
这是一个尝试,但不知道是否可以改进:
主程序包
进口(
“fmt”
“同步”
)
func main(){
客户端:=&sync.Map{}
对于i:=0;i<100;i++{
clientID:=fmt.Sprintf(“客户端-%d”,i%5)
connID:=fmt.Sprintf(“conn-%d”,i)
client,ok:=clients.LoadOrStore(clientID,connID)
如果可以的话{
开关c:=客户端。(类型){
大小写字符串:
客户端=[]字符串{c,connID}
大小写[]字符串:
client=append(客户端([]字符串),connID)
}
clients.Store(clientID,client)
}
}
列表:=func(k,v接口{})bool{
fmt.Printf(“k:%+v:%v\n”,k,v)
返回真值
}
客户机范围(列表)
//获取所有连接
广播:=func(k,v接口{})bool{
fmt.Printf(“到来自%q\n”,k)的所有连接)
对于u,v:=范围v.([]字符串){
fmt.Printf(“连接消息=%s\n”,v)
}
返回真值
}
客户端。范围(广播)
}
在这里,我的仅尝试使用映射(易于处理删除)速度较慢,但分配的字节更少:
主程序包
进口(
“fmt”
“同步”
)
func main(){
客户端:=&sync.Map{}
对于i:=0;i<100;i++{
clientID:=fmt.Sprintf(“客户端-%d”,i%5)
connID:=fmt.Sprintf(“conn-%d”,i)
conns,ok:=clients.Load(clientID)
如果可以的话{
conns.(*sync.Map).Store(connID,i)
}否则{
连接:=&sync.Map{}
康奈德百货公司(康奈德,i)
客户商店(康涅狄格州客户ID)
}
}
列表:=func(k,v接口{})bool{
fmt.Printf(“k:%v\n”,k)
listValue:=func(j,l接口{})bool{
fmt.Printf(“j=%+v\n”,j)
返回真值
}
v、 (*sync.Map).范围(listValue)
返回真值
}
客户机范围(列表)
//获取所有连接
广播:=func(k,v接口{})bool{
fmt.Printf(“到来自%q\n”,k)的所有连接)
listValue:=func(j,l接口{})bool{
fmt.Printf(“连接的消息=%s--%v\n”,j,l)
返回真值
}
v、 (*sync.Map).范围(listValue)
返回真值
}
客户端。范围(广播)
}
package main
import (
"fmt"
"sync"
)
func main() {
clients := &sync.Map{}
for i := 0; i < 100; i++ {
clientID := fmt.Sprintf("client-%d", i%5)
connID := fmt.Sprintf("conn-%d", i)
client, ok := clients.LoadOrStore(clientID, connID)
if ok {
switch c := client.(type) {
case string:
client = []string{c, connID}
case []string:
client = append(client.([]string), connID)
}
clients.Store(clientID, client)
}
}
list := func(k, v interface{}) bool {
fmt.Printf("k: %+v v: %v\n", k, v)
return true
}
clients.Range(list)
// Get all connections
broadcast := func(k, v interface{}) bool {
fmt.Printf("To all connections from= %q\n", k)
for _, v := range v.([]string) {
fmt.Printf("msg to conn = %s\n", v)
}
return true
}
clients.Range(broadcast)
}
package main
import (
"fmt"
"sync"
)
func main() {
clients := &sync.Map{}
for i := 0; i < 100; i++ {
clientID := fmt.Sprintf("client-%d", i%5)
connID := fmt.Sprintf("conn-%d", i)
conns, ok := clients.Load(clientID)
if ok {
conns.(*sync.Map).Store(connID, i)
} else {
conns := &sync.Map{}
conns.Store(connID, i)
clients.Store(clientID, conns)
}
}
list := func(k, v interface{}) bool {
fmt.Printf("k: %v\n", k)
listValue := func(j, l interface{}) bool {
fmt.Printf(" j = %+v\n", j)
return true
}
v.(*sync.Map).Range(listValue)
return true
}
clients.Range(list)
// Get all connections
broadcast := func(k, v interface{}) bool {
fmt.Printf("To all connections from= %q\n", k)
listValue := func(j, l interface{}) bool {
fmt.Printf(" msg to conn = %s -- %v\n", j, l)
return true
}
v.(*sync.Map).Range(listValue)
return true
}
clients.Range(broadcast)
}