Как именно работает эта процедура запуска в анонимной функции?

#go #goroutine

#Вперед #goroutine

Вопрос:

 func (s *server) send(m *message) error {
    go func() {
        s.outgoingMessageChan <- message
    }()
    return nil
}

func main(s *server) {
    for {
        select {
        case <-someChannel:
            // do something
        case msg := <-s.outGoingMessageChan:
            // take message sent from "send" and do something
        }
    }
}
  

Я выхожу из этого s.outgoingMessageChan в другой функции, перед использованием анонимной функции go вызов этой функции обычно блокируется — это означает, что всякий раз, когда send вызывается, s.outgoingMessageChan <- message блокируется до тех пор, пока из него что-то не извлекается. Однако после такой упаковки она, похоже, больше не блокируется. Я понимаю, что она как бы отправляет эту операцию в фоновый режим и выполняется как обычно, но я не могу понять, как это не влияет на текущий вызов функции.

Комментарии:

1. Точно, s.outgoingMessageChan <- message все еще блокируется, но теперь, когда он выполняется в своей собственной goroutine, это не влияет на вашу основную goroutine.

2. Итак, что произойдет, если он перестанет блокировать, но send больше не вызывается?

3. message выполняется нажатие s.outgoingMessageChan , и анонимная подпрограмма завершается. Может быть, попробуйте пересмотреть соответствующие части go tour ? Понимание goroutines имеет решающее значение для написания good go.

Ответ №1:

При каждом send вызове создается новая подпрограмма, которая немедленно возвращается. (Кстати, нет причин возвращать ошибку, если ошибки никогда не может быть.) Goroutine (у которого есть собственный «поток» выполнения) заблокируется, если ничего не готово для чтения из chan (при условии, что оно не буферизовано). Как только сообщение будет прочитано chan , программа goroutine продолжится, но, поскольку она больше ничего не делает, она просто закончится.

Я должен отметить, что не существует такой вещи, как анонимная goroutine. У Goroutines вообще нет идентификатора (за исключением номера, который следует использовать только для целей отладки). У вас есть анонимная функция, перед которой вы помещаете go ключевое слово, заставляющее ее запускаться в отдельной goroutine.

Для функции отправки, которая блокируется, как вам кажется, просто используйте:

 func (s *server) send(m *message) {
    s.outgoingMessageChan <- message
}
  

Однако я не вижу никакого смысла в этой функции (хотя она была бы встроенной и такой же эффективной, как и без использования функции).

Я подозреваю, что вы можете звонить send много раз, прежде чем что-либо будет прочитано из chan. В этом случае будет создано много новых подпрограмм (каждый раз, когда вы вызываете send ), которые все будут блокироваться. Каждый раз, когда chan считывается из одного, он разблокирует доставку своего значения, и эта процедура завершается. Делая это, вы просто создаете неэффективный механизм буферизации. Более того, если send вызывается в течение длительного периода времени с большей скоростью, чем значения могут быть считаны из chan, тогда у вас в конечном итоге закончится память. Лучше было бы использовать буферизованный канал (и никаких программ), который, как только он (канал) стал полным, оказывал «обратное давление» на то, что создавало сообщения.

Еще один момент заключается в том, что имя функции main используется для определения точки входа в программу. Пожалуйста, используйте другое имя для вашей 2-й функции выше. Также кажется, что это должен быть метод (с использованием s *server приемника), а не функция.

Комментарии:

1. Я не могу использовать буферизованные каналы для этого случая, что было бы лучшим способом сделать это? Моей первой интуицией был также буферизованный канал.

2. Если вы хотите буферизировать значения, но не использовать буферизованный канал (почему бы и нет?), Тогда вам нужно как-то их буферизировать, например, путем сохранения в срезе, Или вы можете сделать это, как в вашем исходном сообщении, если вы уверены, что сообщения используются, в долгосрочной перспективе, быстреечем они создаются. Я надеюсь, что этот ответ вам полезен, но я не могу быть более конкретным без дополнительной информации. о том, что вы пытаетесь сделать.

3. Я не могу использовать буферизованный канал, потому что это запрещено в моей домашней работе : : p но я понимаю, что вы имеете в виду. Спасибо за ваш ответ, он был достаточно информативным!