Использование канала или sync.Cond для ожидания условия

Я пытаюсь дождаться определенного состояния и хотел бы посоветовать, как это сделать лучше всего. У меня есть структура, которая выглядит так (упрощенно):

type view struct {
    timeFrameReached bool
    Rows []*sitRow
}

В goroutine я обновляю файл, который читается в view переменная. Количество рядов увеличивается, и timeFrameReached в конечном итоге будет true,

В другом месте я хочу дождаться выполнения следующего условия:

view.timeFrameReached == true || len(view.Rows) >= numRows

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

for {
    view = getView()
    if view.timeFrameReached == true || len(view.Rows) >= numRows {
        break
    }
}

но это, очевидно, наивное решение. Значение numRows исходит из HTTP-запроса, поэтому метод условия выглядит сложным. Программа не будет знать, когда транслировать условие, потому что не будет знать, сколько строк она ищет.

2 ответа

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

Обычный шаблон для этого:

mutex.Lock()
for {
    view = getView()
    if view.timeFrameReached == true || len(view.Rows) >= numRows {
        break
    }
    cond.Wait(&mutex)
}
// Do stuff with view
mutex.Unlock()

Затем в коде, где view изменено:

mutex.Lock()
// Change view
cond.Signal() // or cond.Broadcast()
mutex.Unlock()

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

Вы можете сделать что-то похожее с каналом, отправив на канал сигнал и попытавшись получить сигнал от канала, чтобы подождать, но мне это кажется более сложным. (Кроме того, если у вас есть более одного ожидания программы, вы можете дать сигнал всем им проснуться, используя cond.Broadcast.)

Одна идея, которую я имею, заключается в передаче необходимого количества строк через канал, и процедура, которая строит представление, сделает неблокирующее получение, чтобы увидеть, запрашивает ли основной поток определенное количество строк. Если это так, он отправит сообщение обратно, чтобы указать, что условие выполнено.

Здесь main Функция запрашивает количество строк:

if numRows > len(viewFile.View.Rows) && !viewFile.View.TimeFrameReached {
    // Send the required number of rows
    rows <- numRows
    // Wait for the prefetch loop to signal that the view file is ready
    <-rows // Discard the response value and move on
    view = getView()
}

Здесь программа проверяет, требуется ли определенное количество строк. Если это так, он отвечает утвердительным сигналом, когда готов. Значение этого сигнала несущественно.

select {
    case numRows := <-rows:
        if len(viewFile.View.Rows) >= numRows || viewFile.View.TimeFrameReached {
            rows <- 1
        }
    default:
}
Другие вопросы по тегам