В этом дивном новом асиновом мире c я снова и снова нуждаюсь в приемлемом методе ожидания чего-то, чтобы быть в определенном состоянии или соответствовать определенному условию. Например (псевдокод)
await (myStateMachine.State == StateEnum.Ready);
await (myDownloadProgress == 100.0);
await (mySpiDeviceFifoLEvel != 0);
Эти сценарии ios возникают из-за необходимости удерживать некоторый асинхронно запущенный код, пока не будет достигнуто определенное состояние в другой части кода. Например, пользователь запускает новую часть пользовательского интерфейса, но фоновый поток все еще пытается установить связь sh с частью аппаратного обеспечения. Или конечный автомат, управляющий одним аппаратным обеспечением, должен ждать, пока другой конечный автомат, управляющий другим аппаратным обеспечением, не достигнет определенного состояния готовности. и при этом заметил появление определенных шаблонов, поэтому естественная прогрессия заключается в том, чтобы закодировать нам некоторый вспомогательный класс / generi c для выполнения такого рода поведения повторно.
До того, как я go упаду На этом маршруте должны быть другие, которые решают эту проблему, поэтому мне было интересно, знает ли кто-нибудь об испытанном и проверенном шаблоне или рекомендованном способе сделать это. Я провел некоторые поиски на WWW but и не нашел ничего особенно убедительного. Этот ТАК вопрос затрагивает эту тему, но операционная служба задает другую причину. Этот ТАК * вопрос требует такого же рода вещей, но указывает c на выполнение задачи.
Способы, которые я до сих пор достигал
1. Не делай этого! Используйте событие
Когда я контролирую источник (например, состояние конечного автомата), который меняется, я часто убеждаю себя, что делаю это неправильно, и вместо того, чтобы ждать достижения значения Я должен заставить производителя (конечный автомат) генерировать событие, когда мое условие будет достигнуто. Любой слушатель может затем использовать AutoResetEvent
или ManualResetEvent
для ожидания обработчика
{
myStateMachine.OnMyConditionAchieved += OnConditionAchievedEventHandler;
myEvent = new AutoResetEvent(false);
myEvent.WaitOne();
}
void OnConditionAchievedEventHandler(object sender, EventArgs e)
{
myEvent.Set();
}
Недостатком этого является то, что я действительно не хочу засорять код моего производителя событиями, которые определены c на нужды потребителей.
2. Используйте Событие, накладные расходы на кодирование в зависимости от компромисса производительности
Если уже нет удобного события, которое можно подключить к (1), тогда производитель навсегда изменяется в соответствии с потребностями потребителей. Таким образом, очевидная естественная прогрессия - использовать что-то вроде INotifyPropertyChanged
паттерна. Таким образом, не существует бесконечного расширения для производителей, и потребитель делает это:
void StateMachine_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.Property == "State")
{
if (myStateMachine.State == State.TheStateThatIWant)
{
myEvent.Set();
}
}
}
Это похоже на выигрыш, потому что я часто использую систему NotifyPropertyChanged - это требуется для DataBinding, поэтому меньше кода для добавим, но, кажется, грязно, что мы слушаем каждое изменение в производителе, чтобы отфильтровать условие, которое нужно - конечно, есть лучший способ?!
3. Используйте задачу и опрос (тьфу)
Раскрутите задачу, которая проверяет состояние и спит, если условие не выполняется бесконечно или пока задача не будет отменена. Вызывающие абоненты, а затем дождитесь завершения задачи. Задача завершается, когда условие выполняется или отменяется.
Плюсы - делает для аккуратного кода, особенно при использовании лямбда-подхода Task.Run (() =>…), может использовать методы отмены задачи (токены, тайм-ауты et c), который часто также необходим. Против - опрос кажется грязным, кажется немного тяжелым, чтобы построить совершенно новую задачу для выполнения такой простой работы
4. Используйте задачу и ждите события
Лучше, чем опрос, верно? Но страдает от той же проблемы, что и в 1) и 2) необходимости соответствующего события, к которому необходимо подключиться, поэтому 2) (INotifyPropertyChanged) более распространено, чем 1). Поэтому реализация часто заканчивается ускорением задачи, ожиданием ManualResetEvent, прослушиванием PropertyChanged и фильтрацией изменений, срабатыванием события, возвратом из задачи.
5. Святой Грааль
Я не уверен на 100%, но что-то 1) легкое 2) позволяет указывать условие во время ожидания 3) не будет огромным ресурсным бременем, если 10 000 объектов ожидают в различных свойствах для достижения определенных значений 4) очищают, т.е. правильно распределяют ресурсы
MagicValueWaiter waitForValue = new MagicValueWaiter(MyStateMachine, nameof(State), (s) => (s > 4) && (s < 8));
await waitForInit.WaitAsync();
или
await ValueWaiter.WaitAsync(MyObject, nameof(MyPropertyorField), (s) => (s == States.Init);
Итак в основном, обобщенный c класс / метод для ожидания того, что данное свойство или поле данного объекта удовлетворяет определенному заданному условию в форме лямбда-выражения, возвращающего bool.
Этот подход может на первый взгляд предполагать однако метод опроса, если я заставляю MyObject соответствовать чему-то подобному, должен реализовывать INotifyPropertyChanged или некоторый пользовательский базовый класс для поддержки этого поведения, например ISupportValueWaiting, тогда мы могли бы подключиться к некоторому общему поведению, например, событиям в MyObject, и избежать опроса.
* 1063 Какие-нибудь очевидные решения, которые я пропускаю? Кто-нибудь получил какие-нибудь новые идеи о том, как это сделать? или комментарии по моему?