2013-07-22 6 views
10

Если я колеблюсь по каналу тикера и остановке вызова(), канал остановлен, но не закрыт.Тик-стоп-поведение в Голанге

В этом примере:

package main 

import (
    "time" 
    "log" 
) 

func main() { 
    ticker := time.NewTicker(1 * time.Second) 
    go func(){ 
     for _ = range ticker.C { 
      log.Println("tick") 
     } 
     log.Println("stopped") 
    }() 
    time.Sleep(3 * time.Second) 
    log.Println("stopping ticker") 
    ticker.Stop() 
    time.Sleep(3 * time.Second) 
} 

Running производит:

2013/07/22 14:26:53 tick 
2013/07/22 14:26:54 tick 
2013/07/22 14:26:55 tick 
2013/07/22 14:26:55 stopping ticker 

Так что goroutine никогда не выходит. Есть ли лучший способ справиться с этим делом? Должен ли я беспокоиться о том, что горутин никогда не выходил?

+1

Вы получаете утечку памяти, если обычная процедура не выходит. Нажмите «Закрыть» (ticker.C), чтобы освободить процедуру Go. – fuz

+3

Не удается закрыть его: «невозможно закрыть канал только для приема» – whatupdave

ответ

10

Сигнал «сделанный» на втором канале и выберите в вашем канате между тикером и готовым каналом.

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

11

Используется второй канал, предложенный Фолькером. Это то, что я в конечном итоге работает с:

package main 

import (
    "log" 
    "time" 
) 

// Run the function every tick 
// Return false from the func to stop the ticker 
func Every(duration time.Duration, work func(time.Time) bool) chan bool { 
    ticker := time.NewTicker(duration) 
    stop := make(chan bool, 1) 

    go func() { 
     defer log.Println("ticker stopped") 
     for { 
      select { 
      case time := <-ticker.C: 
       if !work(time) { 
        stop <- true 
       } 
      case <-stop: 
       return 
      } 
     } 
    }() 

    return stop 
} 

func main() { 
    stop := Every(1*time.Second, func(time.Time) bool { 
     log.Println("tick") 
     return true 
    }) 

    time.Sleep(3 * time.Second) 
    log.Println("stopping ticker") 
    stop <- true 
    time.Sleep(3 * time.Second) 
} 
+4

Если ваша работа занимает 4 секунды, вы закроете свой горутин, и она застрянет, пытаясь записать на канал, это единственный читатель. Вы просто хотите переменную состояния на 'for {}' - и не отправляете на канал остановки, просто закройте ее. – Dustin

-1

Если Вам нужно сохранить больше пространства использования каналов пустых структур - структуры {}, который не стоит никакой памяти. И, как упоминалось выше, don.t отправляет что-то в нем - просто закрывается, что фактически посылает нулевое значение.

0

вы можете сделать как этот.

package main 

import (
    "fmt" 
    "time" 
) 

func startTicker(f func()) chan bool { 
    done := make(chan bool, 1) 
    go func() { 
     ticker := time.NewTicker(time.Second * 1) 
     defer ticker.Stop() 
     for { 
      select { 
      case <-ticker.C: 
       f() 
      case <-done: 
       fmt.Println("done") 
       return 
      } 
     } 
    }() 
    return done 
} 

func main() { 
    done := startTicker(func() { 
     fmt.Println("tick...") 
    }) 
    time.Sleep(5 * time.Second) 
    close(done) 
    time.Sleep(5 * time.Second) 
}