2014-10-01 9 views
4

Короткий вариант: Есть ли способ опорожнить канал, не воссоздавая его, или зацикливая его?Как явным образом освободить канал?

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

Теперь, когда транспорт был сброшен/снова подключен, я хочу «очистить» дополнительный канал, чтобы убедиться, что нет никаких других запросов на перезагрузку, которые заставили бы эту вещь снова подключиться.

+0

возможно дубликат [периодически промывке канала в golang] (http://stackoverflow.com/questions/ 17284349/периодически-промывка-канал-в-голанге) – Floegipoky

+0

Можете ли вы уточнить свой вариант использования? В частности, о том, к чему вы снова подключаетесь и почему. Без всех подробностей это звучит для меня, как настоящая проблема, которая должна быть решена, заключается в том, чтобы помещать ненужные данные в ваш канал, а не удалять их после факта. – Floegipoky

+0

@Floegipoky: 2 канала предназначены для отправки и приема данных по сокету, где данные анализируются в другой части кода, который обрабатывает протокол. Если протокол обнаруживает ошибки, я хочу иметь возможность сигнализировать транспортный уровень, который необходим для повторного подключения. Вот почему мне нужен дополнительный канал – Toad

ответ

2

Что вы описываете потому что могут быть законные запросы на повторное подключение к каналу. Вместо того, чтобы пытаться слить канал, я бы рекомендовал отслеживать время.

На вашем канале повторного подключения отправьте время. Когда закончите с повторным подключением, отметьте время. Потребив канал повторного подключения, выбросьте все сообщения, которые старше вашего последнего повторного подключения.

Еще одно решение для блокировки для достижения этого - сделать канал повторного соединения bool. Сообщение «true» для повторного подключения. Когда повторное соединение завершено, опубликуйте «false». Затем используйте канал, пока не найдете «false».

+0

Мне нравится подход с меткой времени. Он по-прежнему едет по каналу, но в этом случае вы правы, что, по крайней мере, я не могу случайно удалить новые запросы. – Toad

7

Невозможно опорожнить канал без петли. Если у вас нет каких-либо параллельных приемников, то вы можете использовать этот простой цикл:

for len(ch) > 0 { 
    <-ch 
} 

Если у вас есть параллельные приемники, а затем использовать цикл:

L: 
for { 
    select { 
    case <-c: 
    default: 
     break L 
    } 
} 
+0

Я бы подумал, что риск сделать это так: если кто-то еще читает этот канал, он может блокироваться. (В моем случае нет дополнительного читателя, но это оговорка стоит отметить) – Toad

+0

ах вы правы. Я пропустил это. – Toad

0

Кажется, что вместо канала сброса вы хотите сбросить goroutine. Он будет иметь вход со стороны, отправляющей сигнал сброса, и выход на приемник. Когда этот горутин получает запрос на повторное подключение, он передает его получателю. Затем он ожидает получения подтверждения от приемника на третьем канале, отбрасывая любые запросы на повторное подключение, которые он получает в это время. Таким образом, 3 канала всего, 1 вход, 1 выход, 1 экст.

2

Другой подход использует sync.Cond и atomic, что-то вдоль линий:

type Server struct { 
    s  chan int 
    r  chan int 
    c  *sync.Cond 
    state uint32 
} 

const (
    sNormal  = 0 
    sQuitting  = 1 
    sReconnecting = 2 
) 

func New() *Server { 
    s := &Server{ 
     s: make(chan int), 
     r: make(chan int), 
     c: sync.NewCond(&sync.Mutex{}), 
    } 
    go s.sender() 
    // go s.receiver() 
    return s 
} 
func (s *Server) sender() { 
    // 
    for { 
     select { 
     case data := <-s.s: 
     //do stuff with data 
     default: 
      s.c.L.Lock() 
     L: 
      for { 
       switch atomic.LoadUint32(&s.state) { 
       case sNormal: 
        break L 
       case sReconnecting: 
       case sQuitting: 
        s.c.L.Unlock() 
        return 
       } 
       s.c.Wait() 
      } 
      s.c.L.Unlock() 
     } 
    } 
} 

//repeat for receiver 

func (s *Server) Reconnect() { 
    var cannotReconnect bool 
    atomic.StoreUint32(&s.state, sReconnecting) 
    //keep trying to reconnect 
    if cannotReconnect { 
     atomic.StoreUint32(&s.state, sQuitting) 
    } else { 
     atomic.StoreUint32(&s.state, sNormal) 
    } 
    s.c.Broadcast() 
} 

playground

+0

Неужели эти блокировки не будут пагубными для производительности? – Toad

+0

@ Загрузите да, но у вас на самом деле не так много вариантов, вы должны использовать какой-то механизм блокировки/атома при работе с параллелизмом. Это единственный способ, о котором я могу думать, без добавления дополнительного канала, например, предложенного Floegipoky. Кроме того, каналы используют свои собственные блокировки, поэтому вы не получите многого. – OneOfOne

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