2016-11-12 3 views
1

У меня есть структура, называемая Hub с помощью метода Run(), который выполняется в своем собственном goroutine. Этот метод последовательно обрабатывает входящие сообщения. Сообщения поступают одновременно от нескольких производителей (отдельные goroutines). Конечно, я использую channel для выполнения этой задачи. Но теперь я хочу скрыть Hub за interface, чтобы иметь возможность выбирать из его реализаций. Таким образом, использование channel в качестве простого поля Hub не подходит.Можно ли скрыть отправку на канал после вызова функции

package main 
import "fmt" 
import "time" 

type Hub struct { 
    msgs chan string 
} 
func (h *Hub) Run() { 
    for { 
     msg, hasMore := <- h.msgs 
     if !hasMore { 
      return 
     } 
     fmt.Println("hub: msg received", msg) 
    } 
} 
func (h *Hub) SendMsg(msg string) { 
    h.msgs <- msg 
} 

func send(h *Hub, prefix string) { 
    for i := 0; i < 5; i++ { 
     fmt.Println("main: sending msg") 
     h.SendMsg(fmt.Sprintf("%s %d", prefix, i)) 
    } 
} 

func main() { 
    h := &Hub{make(chan string)} 
    go h.Run() 
    for i := 0; i < 10; i++ { 
     go send(h, fmt.Sprintf("msg sender #%d", i)) 
    } 
    time.Sleep(time.Second) 
} 

Так я представил Hub.SendMsg(msg string) функцию, которая просто вызывает h.msgs <- msg и которые я могу добавить к HubInterface. И как Go-новичок, интересно, безопасно ли оно с точки зрения параллелизма? И если да - это общий подход в Go?

Детская площадка here.

+3

Да. Я не уверен, как еще ответить, потому что я не уверен, что привело бы вас к тому, что это может быть опасно. – JimB

+0

@JimB, на самом деле, подумав, как это работает под капотом, я понял, что ответ довольно очевиден, поскольку запись на канал является потокобезопасной. –

+1

_A один канал может использоваться в операторах отправки, приемах и вызовах встроенных функций cap и len любым количеством goroutines без дальнейшей синхронизации. Дополнительная информация приведена в разделе [Если я правильно использую каналы, если мне нужно использовать мьютексы?] (http://stackoverflow.com/questions/34039229/if-i-am-using-channels-properly-should-i-need-to-use-mutexes) – icza

ответ

2

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

Если вы обеспокоены тем, убедившись, что абоненты не может случайно ветер с недействительными Hub случаями с nil каналом, один подход, чтобы сделать тип структуры частного (hub) и имеет NewHub() функцию, которая возвращает полностью инициализирована hub завернутый в ваш тип интерфейса. Поскольку структура является частной, код в других пакетах не может попытаться инициализировать ее неполным строковым литералом (или любым строковым литералом).

Тем не менее, это часто можно создавать недопустимые или бессмысленные значения в Go, и это принято: net.IP("HELLO THERE BOB") действует синтаксис, или net.IP{}. Поэтому, если вы считаете, что лучше разоблачить свой тип Hub.

-1

Легкий ответ

Да

Лучше ответ

Нет

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

Скажем, потребитель создает концентратор, как показано ниже: &Hub{}. Совершенно верно ... Кроме того, что все вызовы SendMsg() будут блокироваться навсегда. К счастью, вы поместили их в свои собственные подпрограммы. Значит, ты все еще в порядке? Неправильно. Теперь вы протекаете по ходу. Кажется, прекрасно ... пока вы не запустите это некоторое время. Go поощряет вас иметь действительные нулевые значения. В этом случае &Hub{} недействителен.

Обеспечение SendMsg() не будет блокироваться, может быть достигнуто с помощью select{}, однако вам необходимо решить, что делать, когда вы сталкиваетесь с делом по умолчанию (например, отбрасываете данные). Канал может блокироваться по многим причинам, кроме плохой настройки. Скажем позже, вы делаете больше, чем просто распечатываете данные после чтения с канала. Что делать, если чтение получает очень медленно или блокирует IO. Затем вы начнете отталкивать производителей.

В конечном счете, каналы позволяют не думать о параллелизме ... Однако, если это что-то вроде высокой пропускной способности, то у вас есть немного рассмотреть. Если это производственный код, то вам нужно понять, что ваш API здесь включает блокировку SendMsg().

+2

Это довольно запутанно; вопрос был задан, изменилась ли семантика отправки канала, переместив функцию отправки в функцию, а это не так. '& Hub {}' является недопустимым значением типа full-stop, является ли передача канала внутри вызова функции или нет. – twotwotwo

Смежные вопросы