Предположим, у меня есть метод интерфейса реализован какДизайн с асинхронным/ожиданием - должно ли быть все асинхронное?
public void DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
}
Через некоторое время я понимаю, что я хочу, чтобы изменить его:
public async Task DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
if (!user.HasReward)
{
using(var dbConnection = await DbPool.OpenConnectionAsync())
{
await dbConnection.Update(user, u =>
{
u.HasReward = true;
u.Gold += 1000;
});
}
}
}
Я меняю подпись метода в интерфейсе. Но вызывающие методы были синхронными, и я должен сделать не только их async, но и все дерево вызовов async.
Пример:
void A()
{
_peer.SendResponse("Ping: " + _x.B());
}
double X.B()
{
return _someCollection.Where(item => y.C(item)).Average();
}
bool Y.C(int item)
{
// ...
_z.DoSomething();
return _state.IsCorrect;
}
должен быть изменен на
async void AAsync()
{
_peer.SendResponse("Ping: " + await _x.BAsync());
}
async Task<double> X.BAsync()
{
// await thing breaks LINQ!
var els = new List<int>();
foreach (var el in _someCollection)
{
if (await y.CAsync(item)) els.Add(el);
}
return _els.Average();
}
async Task<bool> Y.CAsync(int item)
{
// ...
await _z.DoSomething();
return _state.IsCorrect;
}
Пострадавшая вызов дерево может быть очень большой (многие системы и интерфейсы), так что это изменение трудно сделать.
Также, когда первый метод A
вызывается из интерфейса, например IDisposable.Dispose
- Я не могу сделать это асинхронным.
Другой пример: представьте, что несколько вызовов A
были сохранены в качестве делегатов. Раньше они просто вызывались с _combinedDelegate.Invoke()
, но теперь я должен пройти через GetInvocationList()
и await
на каждый элемент.
О, рассмотрим также замену свойства getter методом async.
я не могу использовать Task.Wait()
или .Result
, потому что:
- Это тратить
ThreadPool
потоков в приложении сервера - Это приводит к тупиков: если все
ThreadPool
нитиWait
ИНГ нет потоков для завершения любой задачи ,
Итак, вопрос в том, должен ли я сделать абсолютно все свои методы изначально async
, даже если я не планирую вызывать что-либо асинхронное внутри? Разве это не повредит работе? Или как проектировать вещи, чтобы избежать таких сложных рефакторингов?
У вас нет * have *, чтобы сделать методы вызова async - они могут просто выполнить вызов метода async как 'var result = SomeAsyncMethod(). Результат. Таким образом, вы можете разбить «цепочку асинхронизации», пока не будете готовы реорганизовать дальнейшее дерево вызовов. –
* Разве это не повредит работе? * Вероятно, это не так. * Как разрабатывать вещи, чтобы избежать таких сложных рефакторингов? * Асинхронность несет цену - с одной стороны, вы можете лениво отложить все, но с другой стороны, для нетривиальных случаев для этого требуется код для восходящего потока (например, если ваш механизм проверки формы не поддерживает асинхронность, вы в основном SOL и должны блокировать его). –
Заражение дерева вызовов - это вечная мука асинхронных кодовых баз. – usr