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 затем awaits эта задача, которая заставляет ее возвращать незавершенную задачу его абонент.

в конце концов,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, но делает это более разумно, выполняя несколько задач в одном потоке последовательно, прежде чем возвращать поток обратно в пул. Это можно сделать с помощью интеллектуального использования объектов-делегатов.