У меня есть эта функция:
public async Task<string> EagerLoadAllAsync<T>(params Expression<Func<T, object>>[] includeProperties) where T : class
{
var entities = await _repository.EagerLoadAllAsync(includeProperties);
entities.ForEach(l =>
{
var lead = l as Lead;
if (lead.User != null)
{
// We must reduce the amount of data being sent to the client side
lead.User = new Domain.Identities.ApplicationUser { FirstName = lead.User.FirstName, LastName = lead.User.LastName, UserName = lead.User.UserName };
}
});
var json = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(entities, Formatting.Indented, new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
return json;
}
Я думаю, что все еще async
работает с awaitable
функциями, один - для извлечения данных из базы данных, а другой - для преобразования json
.
Мне было интересно, если цикл ForEach
в среднем типе разрушает async
подход?
Есть ли способ сделать это более async
? Должно ли быть более async
?
Прежде чем мне нужно было уменьшить данные, отправляемые клиенту, у меня была эта функция:
public async Task<string> EagerLoadAllAsync<T>(params Expression<Func<T, object>>[] includeProperties) where T : class
{
var json = await Task.Factory.StartNew(async() => JsonConvert.SerializeObject(await await _repository.EagerLoadAllAsync(includeProperties), Formatting.Indented, new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
return json.Result;
}
У Stephan cleary есть отличная запись в блоге об the dangers of using Task.Run in ASP.NET
:
Причина в том, что среда выполнения ASP.NET не имеет представления о том, что вы поставили эту задачу в очередь (используя Task.Run), поэтому она не знает, что фоновая работа даже существует. По разным причинам IIS/ASP.NET приходится периодически перерабатывать ваше приложение. Если у вас есть фоновая работа, когда эта переработка происходит, эта работа загадочно исчезнет.
Когда я создаю метод async
вокруг некоторой асинхронной операции (запрос БД, веб-запрос и т.д.), Я придерживаюсь правила, в котором говорится, что "метод async должен как можно скорее ударить его утверждение await
", то есть, поскольку любой код до ожидание будет выполняться синхронно. Вы можете использовать ConfigureAwait(false)
чтобы избежать возврата в контекст вашего запроса, но это обычно происходит очень быстро. См. " Лучшая практика" для вызова ConfigureAwait для всего кода на стороне сервера, чтобы узнать больше об этом.
Что ForEach
, я бы определенно оценил эту часть, чтобы увидеть, насколько значительным было влияние на асинхронный вызов. Другое тогда, что прочитайте eric lipperts сообщение о ForEach vs foreach
чтобы понять, почему вы не должны его использовать.
Я бы определенно перешел на новый поток ThreadPool только ради десериализации JSON. Это будет стоить вам больше, чтобы вызвать этот поток, чтобы запустить его синхронно. Если ваш JSON не огромен, пойдите с подходом синхронизации.
Обычно вы ожидаете задачи, которые относительно длительные, как I/O. Итак, ожидание вашего звонка на выборку репозитория - это хорошо. Ваш цикл ForEach совсем не плох, но он, вероятно, будет работать лучше, если ваш выбор из репозитория вернет только нужные вам данные, поскольку он не вернет все эти данные.
Я не уверен, что если вы перейдете к другой задаче, чтобы преобразовать сущности в json, вы делаете все возможное.
И тогда мы должны учитывать, что это веб-вызовы и ждут, просто освобождая обработчик запросов, чтобы он не мог ускорить каждый индивидуальный вызов, он просто не свяжет запрос, который сидит там, ожидая ввода/вывода базы данных,
Вы всегда можете поставить некоторые Stopwatches
чтобы посмотреть, как долго все это происходит.
Task.Run
/Task.Factory.StartNew
/ etc безawait
. Если вы используетеawait
, то кодTask.Run
логически считается частью этого запроса и не «исчезнет». Однако я все еще не рекомендуюTask.Run
на ASP.NET по соображениям эффективности.