Async / Await VS Task.Run: когда использовать? Как пользоваться?
хорошо, я надеюсь, что у меня есть основы async/await, но все же некоторые вопросы снова задерживаются в моей голове.
но сейчас это проблема, о которой я говорю . Предположим, в этом простом примере
static void Main(string[] args)
{
Method();
Console.WriteLine("Main Thread");
Console.ReadLine();
}
public async static void Method()
{
await Task.Run(new Action(LongTask));
Console.WriteLine("New Thread");
}
public static void LongTask()
{
Thread.Sleep(8000);
Console.WriteLine("Long Task");
}
основной поток все еще продолжается и печатает Main Thread
после вызова метода () и встречи с ожиданием в течение 8 секунд .
поэтому, соответственно, метод () возвращается вызывающему, т. е. к основной функции здесь, как только он встречает await, сохраняет синхронизацию контекст и продолжает выполняться оттуда .
печати Main Thread
первый .
затем после 8 секунд в комплекте , Long Task
а то New Thread
распечатать.
эту часть я получил . Мой вопрос находится в моем приложении:
public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)
{
.............
SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);
var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
}
console.writeline("Async called");
return AcctLst;
}
public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
..........................
SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);
var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam);
return AcctLst;
}
здесь createCase
возникновение и ждут
он должен немедленно вернуться вправо и выполнить следующую строку и распечатать Async called
даже до того, как SaveCaseSearch завершится правильно ?
ладно, если Я думаю, громко это может быть control returns to the caller
.
а если я обернуть мой вызов SavCaseSearch
внутри другого метода async / await с именем suppose
async DoWork() {....
}
и назвать это DoWork()
С CreateCase()
прямо так тогда
It will go on printing "Async called" once call to DoWork() encounters await and before it even completes ?
правильно ли я думаю ?
также иногда я вижу и путаюсь между
await someAsync()
и
await Task.Run(() => someAsync())
..
в чем разница между ними ? и за кем следовать ?
4 ответов
мой вопрос в моем заявлении :
ваш код не будет компилироваться, потому что вы используете await
без async
. Исправленный код будет:
public async Task<IList<createcaseoutput>> createCaseAsync(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)
{
...
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
console.writeline("Async called");
return AcctLst;
}
здесь также createCase сталкивается с await, и он должен немедленно вернуться вправо и выполнить следующую строку и распечатать асинхронный вызов, прежде чем даже SaveCaseSearch завершится правильно ?
нет. Этот код:
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
- это то же, что и этот код:
var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
await saveTask;
Итак, во-первых, createCaseAsync
назвали бы saveCaseSearchAsync
. Предположительно,saveCaseSearchAsync
выполняет некоторую асинхронную операцию, поэтому он вернет незавершенную задачу createCaseAsync
. createCaseAsync
затем await
s эта задача, которая заставляет ее возвращать незавершенную задачу его абонент.
в конце концов,saveCaseSearchAsync
завершит, который завершит задачу, которую он вернул (которую я назвал saveTask
в коде выше). Это, в свою очередь, продолжит выполнение createCaseAsync
, и он перейдет к следующей строке и напечатает "async called" на консоли.
так это похоже, если я оберну свой вызов SavCaseSearch внутри другого метода async/await
вам не понадобится обертка, потому что createCaseAsync
уже вернувшись в Task
.
в чем разница между ними ? и за кем следовать ?
Task.Run
главным образом для нажимать преграждая работу с потока УИ и на класса ThreadPool. Так как ты на ASP.NET не используйте Task.Run
.
первое правило асинхронность всегда использовать async или не использовать async.
Если ваш базовый API не может обрабатывать асинхронность, нет смысла использовать асинхронность в верхних слоях (например ASP.NET MVC), так как в какой-то момент Вы получите голодание потока, поскольку все потоки заняты ожиданием операций ввода-вывода (например, вызовов DB).
ваш пример-классический случай, когда вы смешиваете синхронизацию и асинхронность. The Sleep
вызов заблокирует поток до его завершения. Вы должны были использовать Task.Delay
вместо как бы выпустили нить до задержки завершения.
мой совет вам просто начать, следуя правилу, которое я упомянул первым и только тогда, когда IO связаны операции, такие как DB или файловые вызовы участвуют. Затем, когда вы лучше понимаете асинхронность, вы можете начать ее нарушать, так как тогда у вас будет гораздо лучшее понимание того, к чему она может привести.
(Извините, что не отвечаю на ваши вопросы напрямую, но резьба-сложная тема, и ваш мозг может поджарить, если вы пытаетесь получить все сразу. Начать с малого.)
здесь также createCase сталкивается с await, и он должен немедленно вернуться вправо и выполнить следующую строку и распечатать асинхронный вызов, прежде чем даже SaveCaseSearch завершится правильно ?
Это даже не должно компилироваться. Оператор "await" может использоваться только в методе "async". Тем не менее, если вы удалите оператор "await", то следующая строка будет печатать "async called" даже до saveCaseSearch
завершается.
Я думаю в правильный путь ?
saveCaseSearch
уже является "асинхронным" методом, поэтому вам не нужно обертывать его для достижения желаемого результата. Тем не менее, вы можете обернуть его другим методом, если вы действительно хотите.
в чем разница между ними ? и за кем следовать ?
оператор "await" ждет объекта задачи, поэтому любой из них в порядке. Я бы выбрал await someAsync()
, потому что это меньше кода писать.
Что касается разницы между async / await и задачами...
Async / Await являются синтаксическими ключевыми словами для упрощения кода, так как все, прежде чем ключевое слово await происходит в вызывающем потоке, и все, начиная с await, происходит в продолжении задачи.
настройка этого с помощью задач с использованием TPL потребует много кода и читаемость страдает. Обратите внимание, однако, что под ним все еще используются задачи и Продолжения.
кроме того, они не всегда могут использоваться вместо задач, таких как при завершении задание является недетерминированным, или если у вас есть несколько уровней задач наряду с использованием TaskCompletionSource.
для получения дополнительной информации прочитайте главу 4 " асинхронное программирование "в книге"написание высокопроизводительного кода .NET " by Ben Watson
Примечание также, внутренне, TPL использует пул потоков .NET, но делает это более разумно, выполняя несколько задач в одном потоке последовательно, прежде чем возвращать поток обратно в пул. Это можно сделать с помощью интеллектуального использования объектов-делегатов.