我有一个使用2个go例程的聊天应用程序。我想在一个线程中向/从列表中删除记录,或者从另一个线程中读取相同的列表。
由于我在Go语言中还很陌生,所以我对应该使用哪种数据结构感到有些困惑。我想到了切片,但不确定是否以正确的方式使用它]
func listener(addr *net.UDPAddr, clients *[] *net.UDPAddr, messages chan clientMessage) {
for {
*clients=append(*clients,otherAddr)
}
}
func sender(messages chan clientMessage,clients *[] *net.UDPAddr) {
for {
message :=<- messages
for _,client := range *clients {
fmt.Printf("Message %s sent to %s\n", message.message, client.String())
}
}
}
func main() {
var clients [] *net.UDPAddr
go listener(s,&clients,messageCh)
go sender(messageCh,&clients)
}
对于该场景,切片看起来不错,但是需要mutex来防止并发读取和写入切片。
让切片和互斥锁捆绑在一个结构中,并为两个操作添加方法:添加和枚举。
type clients struct {
mu sync.Mutex
values []*net.UDPAddr
}
// add adds a new client
func (c *clients) add(value *net.UDPAddr) {
c.mu.Lock()
c.values = append(c.values, value)
c.mu.Unlock()
}
// do calls fn for each client
func (c *clients) do(fn func(*net.UDPAddr) error) error {
c.mu.Lock()
defer c.mu.Unlock()
for _, value := range c.values {
if err := fn(value); err != nil {
return err
}
}
return nil
}
像这样使用它:
func listener(addr *net.UDPAddr, clients *clients, messages chan clientMessage) {
for {
clients.add(otherAddr)
}
}
func sender(messages chan clientMessage, clients *clients) {
for {
message := <-messages
clients.do(func(client *net.UDPAddr) error {
fmt.Printf("Message %s sent to %s\n", message.message, client.String())
return nil
})
}
}
func main() {
var clients clients
go listener(s, &clients, messageCh)
go sender(messageCh, &clients)
}
由于侦听器只需要写,发送者只需要读-这是使用通道进行通信的一个很好的例子。流程如下所示:
这样会更清洁,更安全-因为侦听器将无法“意外”读取并且发送者将无法“意外”写入。侦听器也可以关闭频道,以向发送方指示已完成。