Чтение / запись набора записей в различных go подпрограммах - какую структуру данных использовать - PullRequest
1 голос
/ 08 мая 2020

У меня есть приложение чата, использующее 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) 
}

Ответы [ 2 ]

3 голосов
/ 08 мая 2020

Так как слушателю нужно только писать, а отправителю нужно только читать - это хороший пример использования каналов для связи. Поток будет выглядеть следующим образом:

  1. Слушатель отправит нового клиента в канал.
  2. Отправитель получит нового клиента и обновит его локальный сегмент клиентов.

Это будет намного чище и безопаснее - так как слушатель не сможет «случайно» прочитать, а отправитель не сможет «случайно» написать. Слушатель также может закрыть канал, чтобы указать отправителю, что это сделано.

2 голосов
/ 08 мая 2020

Срез выглядит нормально для сценария, но мьютекс необходим для предотвращения одновременного чтения и записи в срез.

Давайте объединим срез и мьютекс в структуру и добавьте методы для двух операций: add и enumerate.

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)
}
...