Все рутины спят - тупик (бесконечный цикл + выбор) - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть приложение, которое каждые несколько секунд создает процедуру извлечения текущей цены из API.Затем он отправляет ответ в программу Monitor для анализа.Если монитор обнаружит, что цена значительно изменилась, он отправит уведомление.

Работает нормально, если задержка между каждым прогоном велика.Это не так, если оно маленькое: «фатальная ошибка: все горутины спят - тупик!»срабатывает и происходит сбой программы.

Я предполагаю (?), что тупик вызван тем, что (1) монитор залил новой ценовой информацией (и не успел своевременно их проанализировать);или (2) главная функция заполняется сообщениями от монитора.

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

Как это можно решить?Читая другие посты здесь, я подумал, что утверждение "select" было бы волшебным лекарством, но, похоже, это не ...

func main() {
    ec := make(chan entry, 10)
    mce := make (chan entry, 10)
    mcn := make(chan string, 10)

    go monitor(mce, mcn)

    for {
        go fetchData(ec)
    select {
        // get entries
        case newEntry := <- ec:
            log = append(log, newEntry)
            mce <- newEntry
        default:
            {}
        }

        //check if any notifications received
        select {
        case newMsg := <- mcn:
            fmt.Println(newMsg)
        default:
            {}
        }

        delay()
    }
}

func monitor(mce <-chan entry, mcn chan<- string) {


    for {
        newEntry = <- mce

        for _, item := range log {
            // here - do some analysis comparing the newEntry against previous entries
            // (essentially to see if notification should be triggered)
        }

        if should_send_notification {
            mcn <- msg
        }

    }
}

func fetchData(ec chan<- entry) {

    // here some code fetching newEntry from APIs

    // send the newEntry back to the main function
    ec <- newEntry

}

1 Ответ

0 голосов
/ 26 декабря 2018

Вам нужно только объединить select на одном и удалить оператор по умолчанию для главной функции.При удалении оператора по умолчанию вам не нужна функция delay (), потому что регистр выбора работает, блокируя и ожидая некоторое сообщение от каналов:

func main() {
    ec := make(chan entry, 10)
    mce := make (chan entry, 10)
    mcn := make(chan string, 10)

    go monitor(mce, mcn)
    go fetchData(ec)
    for {
        select {
            // get entries
            case newEntry := <- ec:
                log = append(log, newEntry)
                mce <- newEntry
            //check if any notifications received
            case newMsg := <- mcn:
                fmt.Println(newMsg)
        }
    }
}

fetchData (ec) удобно реализовывать как блокирование и выполнениене называйте это постоянно:

func fetchData(ec chan<- entry) {

    for {
        // here some code fetching newEntry from APIs
        // waiting data

        // send the newEntry if I get data
        ec <- newEntry
    }

}
...