С Новым Годом!)
В asp.net приложении на .net 4.8 есть синхронный акшн, в глубинах реализации (через длинную цепочку вызовов) надо использовать асинхронный метод (c кивордом async который).
упрощённый пример ситуации ниже
static async Task<bool> DoWork(string msg) {
//some work
await Task.Delay(1000); //так виснет
await Task.Delay(1000).ConfigureAwait(false); //так норм!
return true;
}
//метод контроллера
public void SomeControllerAction() {
var t = DoWork("test");
var r = t.Result; //тут виcнет
//other work
}
дак вот, при вызове у таски, возвращённой от async функции, .Result — на ней виснет и управление не возвращается.
виснет после 1-го вызова await в async функции.
суть проблемы раскопал — оказывается по умолчанию, после await, система пытается возвратить управление в исходный поток из которого был вызван await
но, исходный поток заблокирован на .Result — deadlock
в качестве лечения предлагается — после вызова таски для await добавлять .ConfigureAwait(false)
это типа не принуждает после await-а продолжить выполнение на исходном потоке.
такое поведение вызывает вопросы
1. зачем такое дефолтное поведение в asp.net? ведь при async/await-ах и так подразумевается что после окончания ожидания управление может продолжено свободным потоком из пула.
идея продолжения в исходном хуже и с точки зрения перфа — исходный поток мог уже быть назначен для выполнения другой таски и занят.
понятен кейс такого поведения — в UI приложениях, актуально чтоб продолжили в том же потоке откуда было вызвано, но для этого
в таких случаях можно и вызывать .ConfigureAwait(true) или даже вызывать только на рутовой таске, а вложенные наследуют заданное поведение (await происходит же из таски, и можно получить доступ к её опциям).
либо какую-то глобальную настройку выставлять в UI приложениях.
в asp.net так не надо, т.е. из-за частного случая сделали неудобное поведение.
2. почему нет глобальной настройки? или для рутовой таски указать стратегию для вложенных await-ах?
3. зачем об этом думать
при каждом await ? а .ConfigureAwait(false) надо вызвать при каждом во всей цепочке
это какое-то неудачно решение дизайна?
или есть какие-то причины которые от меня ускользнули?