Остановить выполнение программы по таймауту - PullRequest
0 голосов
/ 28 мая 2018

Я хочу остановить выполнение goroutine по таймауту.Но похоже, что это не работает для меня.Я использую iris framework.

  type Response struct {
    data   interface{}
    status bool
  }

  func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)

    go func() {
      time.Sleep(10 * time.Second)

      fmt.Println("test")
      fmt.Println("test1")

      ch <- Response{data: "data", status: true}
    }()

    select {
    case <-ch:
      fmt.Println("Read from ch")
      res := <-ch
      return res.data, res.status
    case <-time.After(50 * time.Millisecond):
      return "Timed out", false
    }

  }

Вывод:

 Timed out
 test
 test1

Ожидаемый вывод:

 Timed out

Может кто-нибудь указать, чего здесь не хватает?Это делает тайм-аут, но все еще запускает goroutine для печати test и test1.Я просто хочу остановить выполнение горутина, как только истечет время ожидания.

Ответы [ 3 ]

0 голосов
/ 29 мая 2018

Лучший способ управлять обработкой рутин - это контекст (библиотека std go).

Вы можете отменить что-либо внутри программы и остановить выполнение без возможностиутечка рутины .

Здесь просто пример с отменой по таймауту для вашего случая.

ctx, cancel := context.WithCancel(context.Background())
ch := make(chan Response, 1)

go func() {
    time.Sleep(1 * time.Second)

    select {
    case <-ctx.Done():
        fmt.Println("Canceled by timeout")
        return
    }

    fmt.Println("test")
    fmt.Println("test1")

    ch <- Response{data: "data", status: true}
}()

select {
case <-ch:
    fmt.Println("Read from ch")
case <-time.After(50 * time.Millisecond):
    fmt.Println("Timed out")
    cancel()
}
0 голосов
/ 28 июня 2018

У вас есть утечка гурутина, вы должны выполнить какое-то действие, чтобы вернуть горутин до истечения времени ожидания, как это:

func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)
    done := make(chan struct{})
    go func() {
        select {
        case <-time.After(10 * time.Second):
        case <-done:
            return
        }
        fmt.Println("test")
        fmt.Println("test1")
        ch <- Response{data: "data", status: true}
    }()
    select {
    case res := <-ch:
        return res.data, res.status
    case <-time.After(50 * time.Millisecond):
        done <- struct{}{}
        return "Timed out", false
    }

}
0 голосов
/ 28 мая 2018

Нет хорошего способа «прервать» выполнение программы в середине ее выполнения.

Go использует модель параллельного соединения fork-join, это означает, что вы «разветвляетесь», создавая новую программу, а затем не контролируете, как эта программа запланирована, пока вы не достигнете «точки соединения».Точка соединения - это своего рода синхронизация между несколькими программами.например, отправка значения по каналу.

Используя ваш конкретный пример, эта строка:

ch <- Response{data: "data", status: true}

... сможет отправлять значение, несмотря ни на что, потому что это буферизованный канал.,Но тайм-аут, который вы создали:

case <-time.After(50 * time.Millisecond):
  return "Timed out", false

Эти тайм-ауты находятся на «получателе» или «считывателе» канала, а не на «отправителе».Как упоминалось в верхней части этого ответа, нет способа прервать выполнение программы без использования некоторых методов синхронизации.

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

...