координация и аккуратное закрытие рутин - PullRequest
0 голосов
/ 28 апреля 2019

Я совершенно новичок в Go, только учусь (в данный момент я играю с каналами и занимаюсь рутиной, я пытаюсь понять координацию).Я застрял с проблемой.

Я не понимаю, что происходит за кулисами, когда я начинаю 2 идти рутины.ServiceAlpha отвечает за установку тактового импульса на ServiceBeta и за смерть, если он получает событие прерывания на канале прерывания. ServiceBeta отвечает за запись какой-то глупой строки в мой вывод журнала, и у него есть TTL (он исходит от serviceAlpha), поэтому, если он не получает пульс вВремя TTL должно завершить свою работу и вернуться к своему вызывающему, но перед выходом должно выдать какое-либо событие abort ServiceAlpha на канале abort

Моя проблема Я не понимаю, почему он продолжает работать после TTL и

вывод выглядит следующим образом:

2019/04/28 17:21:44 Main | START
2019/04/28 17:21:44 serviceBeta | START
2019/04/28 17:21:44 serviceAlpha | START
2019/04/28 17:21:44 serviceAlpha | There was not abort
2019/04/28 17:21:44 serviceAlpha | rand = 3
2019/04/28 17:21:45 serviceBeta | TICKER:  2019-04-28 17:21:45.2870594 +0200 CEST m=+1.003883901
2019/04/28 17:21:46 serviceBeta | TICKER:  2019-04-28 17:21:46.2867957 +0200 CEST m=+2.003620201
2019/04/28 17:21:47 serviceBeta | TICKER:  2019-04-28 17:21:47.2866242 +0200 CEST m=+3.003448701
2019/04/28 17:21:47 serviceAlpha | There was not abort
2019/04/28 17:21:47 serviceAlpha | rand = 5
2019/04/28 17:21:48 serviceBeta | TICKER:  2019-04-28 17:21:48.2869918 +0200 CEST m=+4.003816301
2019/04/28 17:21:49 serviceBeta | TICKER:  2019-04-28 17:21:49.2863265 +0200 CEST m=+5.003151001
2019/04/28 17:21:50 serviceBeta | TICKER:  2019-04-28 17:21:50.2868071 +0200 CEST m=+6.003631601
2019/04/28 17:21:51 serviceBeta | TICKER:  2019-04-28 17:21:51.2866738 +0200 CEST m=+7.003498301
2019/04/28 17:21:51 serviceBeta | ABORT 2019-04-28 17:21:51.2866738 +0200 CEST m=+7.003498301

Keeps running...
missing serviceBeta: STOP
and ServiceAlpha,and Main also

Я почти уверен, что есть много проблем с этим кодом, поэтому мои вопросы - В чем проблема в этом дизайне?:) - Как правильно его кодировать?

Буду признателен за любую помощь!

Дарви

package main

import (
    "log"
    rand2 "math/rand"
    "sync"
    "time"
)

func main() {
    log.Println("Main | START")
    var wg sync.WaitGroup
    var resetTTL = make(chan interface{})
    var abort = make(chan interface{})
    defer func() {
        log.Println("Main | defer closing channels")
        close(resetTTL)
        close(abort)
    }()

    wg.Add(1)
    go serviceAlpha(1, 5, resetTTL, abort, &wg)

    wg.Add(1)
    go serviceBeta(4*time.Second, resetTTL, abort, &wg)

    wg.Wait()
    log.Println("Main | STOP")
}

func serviceAlpha(min, max int, ttlReset chan<- interface{}, abort <-chan interface{}, wg *sync.WaitGroup) {
    log.Println("serviceAlpha | START")
    var randTTL int
loop:
    for {
        select {
        case <-abort:
            log.Println("serviceAlpha | There was an abort, breaking from loop")
            break loop
        default:
            log.Println("serviceAlpha | There was not abort")
            break
        }

        randTTL = rand2.Intn(max-min) + min + 1
        log.Printf("serviceAlpha | rand = %v", randTTL)
        time.Sleep(time.Duration(randTTL) * time.Second)
        ttlReset <- true
    }

    log.Println("serviceAlpha | STOP")
    wg.Done()
}

func serviceBeta(ttl time.Duration, ttlReset <-chan interface{}, abort chan<- interface{}, wg *sync.WaitGroup) {
    log.Println("serviceBeta | START")
    var ttlTimer = time.NewTimer(ttl)
    var tickerTimer = time.NewTicker(1 * time.Second)

loop:
    for {
        select {
        case <-ttlReset:
            ttlTimer.Stop()
            ttlTimer.Reset(ttl)
        case tt := <-tickerTimer.C:
            log.Println("serviceBeta | TICKER: ", tt)
        case ttl := <-ttlTimer.C:
            log.Println("serviceBeta | ABORT", ttl)
            break loop
        }
    }

    abort <- true

    log.Println("serviceBeta | STOP")
    wg.Done()
}

Ответы [ 2 ]

0 голосов
/ 28 апреля 2019

Хотя ваше решение может работать в этом случае, оно все еще является недостатком дизайна.Проблема в исходном коде заключалась в эффективной тупиковой ситуации, когда serviceAlpha пытался записать в ttlReset, в то время как serviceBeta больше не слушал этот канал.Это блокирует serviceAlpha.Теперь serviceBeta хочет записать в abort, но serviceAplha в настоящее время не слушает его, что также блокирует serviceBeta.Использование буферизованного канала работает, потому что он больше не блокирует.

Однако я смог использовать тикер вместо сна и заставить его работать.Вот модифицированный код для serviceAlpha:

   func serviceAlpha(min, max int, ttlReset chan<- interface{}, abort <-chan interface{}, wg *sync.WaitGroup) {
    log.Println("serviceAlpha | START")
    var randTTL int
loop:
    for {
        randTTL = rand2.Intn(max-min) + min + 1
        log.Printf("serviceAlpha | rand = %v", randTTL)
        ticker := time.NewTicker(time.Duration(randTTL) * time.Second)
        select {
        case <-abort:
            log.Println("serviceAlpha | There was an abort, breaking from loop")
            break loop
        case <-ticker.C:
            log.Println("serviceAlpha | There was not abort")
            ttlReset <- true
        }
    }

    log.Println("serviceAlpha | STOP")
    wg.Done()
}
0 голосов
/ 28 апреля 2019

Я только что понял это! :) Rubber_duck_debugging

abort нуждается в емкости 1;) и проверка сброса должна выполняться одновременно с попыткой сброса TTL

var abort = make(chan interface{}, 1)
func serviceAlpha(min, max int, ttlReset chan<- interface{}, abort <-chan interface{}, wg *sync.WaitGroup) {
    log.Println("serviceAlpha | START")
    var randTTL int
loop:
    for {
        randTTL = rand2.Intn(max-min) + min + 1
        log.Printf("serviceAlpha | rand = %v", randTTL)
        time.Sleep(time.Duration(randTTL) * time.Second)

        select {
        case <-abort:
            log.Println("serviceAlpha | There was an abort, breaking from loop")
            break loop
        default:
            log.Println("serviceAlpha | There was not any abort event")
            ttlReset <- true
            break
        }
    }

    log.Println("serviceAlpha | STOP")
    wg.Done()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...