#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 но я понимаю, что вы имеете в виду. Спасибо за ваш ответ, он был достаточно информативным!