嗨,大家好,我正在尝试使用websocket建立一个聚会系统,使人们可以进入队列,然后与5个与他们相似的人相匹配。现在,我在这部分上遇到了麻烦:
type PartyHub struct {
Partys map[string]*Party
PartialPartys []*PartialParty
Queue []*Member
AddParty chan *Party
RemoveParty chan *Party
AddPartialParty chan *PartialParty
RemovePartialParty chan *PartialParty
EnterQueue chan *Member
LeaveQueue chan *Member
Mu sync.Mutex
}
// Run will begin monitoring the channels
// to register and unregister partys as they are
// created or destroyed
func (p *PartyHub) Run() {
for {
select {
case member := <-p.EnterQueue:
go p.SortMemberIntoParty(member)
go p.SortMemberIntoParty(member)
go p.SortMemberIntoParty(member)
go p.SortMemberIntoParty(member)
go p.SortMemberIntoParty(member)
log.Println(p.PartialPartys)
case party := <-p.AddPartialParty:
p.Mu.Lock()
defer p.Mu.Unlock()
p.PartialPartys = append(p.PartialPartys, party)
}
}
}
// SortMemberIntoParty will take a new user entering the queue and find an appropriate Party
// for the member to join, taking into account RankTollerance, Rank
func (p *PartyHub) SortMemberIntoParty(member *Member) {
p.Mu.Lock()
defer p.Mu.Unlock()
if len(p.PartialPartys) == 0 {
log.Println("Here")
newParty := &PartialParty{Accepting: true, Members: []*Member{member}}
p.AddPartialParty <- newParty
return
}
foundPartyForMember := false
for _, party := range p.PartialPartys {
goodFitForParty := true
for _, partyMember := range party.Members {
log.Println(member.Type == partyMember.Type, member.Rank >= partyMember.Rank-partyMember.RankTol, member.Rank <= partyMember.Rank+partyMember.RankTol)
if member.Type == partyMember.Type && member.Rank >= partyMember.Rank-partyMember.RankTol && member.Rank <= partyMember.Rank+partyMember.RankTol {
goodFitForParty = true
continue
} else {
goodFitForParty = false
break
}
}
if !goodFitForParty {
continue
} else {
foundPartyForMember = true
party.Mu.Lock()
defer party.Mu.Unlock()
party.Members = append(party.Members, member)
if len(party.Members) == 5 {
party.Accepting = false
go party.SendReadyCheck()
}
break
}
}
if !foundPartyForMember {
newParty := &PartialParty{Accepting: true, Members: []*Member{member}}
p.AddPartialParty <- newParty
}
log.Println("Sorting Members")
}
唯一的问题是,这5个文件goroutines
似乎比数据所知道的快得多。
例如:p.PartialPartys
说没有聚会。
我需要的是p.PartialPartys
始终对goroutine
访问该PartyHub
结构的该字段的每个对象保持最新状态,尽管这sync.Mutex
会为我做到这一点,但事实并非如此,有人可以告诉我保留所有goroutine的最佳方法吗?与相同数据同步?
因此,使用此实现,您的五个goroutine都将无法并行运行,因为它们都试图使p.Mu
互斥体无罪。再看看您使用p.AddPartialParty
通道的方式,如果代码可能出现死锁,我也不会感到惊讶。
请考虑以下事件序列:
SortMemberIntoParty
goroutine开始运行并获取互斥量。p.AddPartialParty
,由接收Run
。Run
然后尝试获取互斥锁,因此阻塞。SortMemberIntoParty
goroutine完成并释放互斥量。SortMemberIntoParty
goroutine获取互斥量,然后尝试将另一个值发送给p.AddPartialParty
。Run
在互斥体返回select
语句之前仍在等待该互斥体)。因此,现在您有了一个阻塞的goroutine,该例程持有通道的接收端所需的锁。另请注意,在(4)处您将看不到新内容,PartialParty
因为Run
尚未设法添加它。
如果确实需要互斥锁,那么直接进行SortMemberIntoParty
goroutine更新p.PartialPartys
而不是使用通道可能会更容易:您已经知道没有其他人可以同时访问该变量。
还值得记住的是,这个互斥锁本质上意味着所有SortMemberIntoParty
goroutine将被序列化。如果您使用goroutines希望在这里实现并行性,则互斥锁会克服这一点。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句