2016-04-13 2 views
2

Я просто новичок в этом мире асинхронного материала.
Пожалуйста, несите мою нехватку знаний.Async/await vs Task.Run in C#

  1. Говорит, когда метод встреча ждет ... «Он рассказывает awaitable запустить оставшуюся часть метода, когда он завершает, а затем возвращается из метода асинхронного.»
    я не сделал получите эту часть.
    Значит ли это, что метод все еще продолжает работать синхронно и ждет до ожидаемого возвращения, а затем переходит к остальной части метода?
    Если нет, объясните, почему тогда Task.Run необходим для запуска метода в фоновом режиме или в режиме пожара и забыли способ. Я все еще мог быть достигнут через Ожидать также правильно? то есть
    Метод продолжает выполнять остальные операторы, не дожидаясь возвращения ожидания.
    Надеюсь, что это похоже на подход фона. Или не так ли? Я запутался.

  2. Если метод отмечен асинхронной и ждут, и что в свою очередь вызывает другой метод асинхронно в отдельном слое, который также отмечен с асинхронной и поджидают ..
    тогда как вызов первого метода, который отмечен в асинхронном и ждать от отдельного метода сказать имя ABC должно выглядеть?
    Я не хочу комментировать этот метод для async/await. Таким образом,

    Task.Run(() => DoWork()); 
    

    от ABC() в порядке, без маркировки async/wait?
    Или это против принципа асинхронности?

Вот что я пытаюсь достичь ...

public IList<CreateCaseOutput> ABC(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput) 
    { 
     CaseSQL.getABCParameters(CreateCaseInput, RequestType, out strSPQuery, out listParam); 
     var AcctLst = rep.ExecuteStoredProcedure<CreateCaseOutput>(strSPQuery, listParam).ToList(); 

     if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString())) 
     { 
      Task.Run(async() => 
      { 
       await DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 
      }).ConfigureAwait(false);    
     } 
     console.writeLine("After Async called"); 
     return AcctLst; 
    } 

    public async Task<SaveCaseSearchOutput>> DEF(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key) 
    { 

      CaseSQL.getDEFParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam); 
      var AcctLst = await rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(strSPQuery, listParam); 
      return AcctLst; 
    } 

DEF, который асинхронной/Await должна вызываться в фоновом режиме в огонь и забыть подход от ABC и один раз выстрелил я хочу продолжить с остальной частью ABC и запустить DEF в фоновом режиме. Что случилось в этом огне и забыть о подходе? Если я называю

только

DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 

вместо

Task.Run(async() => 
       { 
        await DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 
       }).ConfigureAwait(false);    
      } 
      return AcctLst; 

этот код работает синхронно в отладчике.

Я что-то не так?

+0

Я хочу объяснить, но это уже здесь с простотой, посмотрите, помогает ли это https://stephenhaunts.com/2014/10/10/simple-async-await-example-for-asynchronous-programming/ – PKV

+1

Хорошее объяснение [здесь] (http://stackoverflow.com/q/25078668/2530848) также обязательно проверьте [вступительную статью] Stephen (http://blog.stephencleary.com/2012/02/async-and-await. html) –

+0

Я использую Run, чтобы выполнить синхронное выполнение задачи (работает в пуле потоков задач). т. е. '' 'var task = Task.Run (() => DoWork());/** сделать что-то еще **/ждать, '' ' –

ответ

5

Значит ли это, что метод все еще продолжает работать синхронно и ждет до ожидаемого возвращения, а затем переходит к остальной части метода?

№ Ожидаемый механизм «обратного вызова». Таким образом, метод просто регистрируется с ожидаемым. Когда он будет завершен, он выполнит свои обратные вызовы, которые включают в себя продолжение метода async.

В то же время метод async возвращает неполную задачу.

Если нет, объясните, почему Task.Run необходим для запуска метода в фоновом режиме или в режиме огня и забывания.

Если вы хотите работать на фоновом потоке, а затем использовать Task.Run. Task.Run просто планирует работу в пуле потоков.

Я все еще мог быть достигнут через ожидание также правильно? т. е. Метод продолжает выполнять остальные операторы, не дожидаясь возвращения ожидания. Надеюсь, что это похоже на подход фонового пробега. Или не так ли? Я запутался.

Ну, вы могли бы «забыть» задачу, просто не в ожидании его:

MyMethod() 
{ 
    SomeMethodAsync(); // Note: no await; we just ignore the task. 
} 

Вы почти никогда не хотите сделать «огонь и забыть», хотя. Легко> 90% времени люди просят об этом, это на самом деле ошибка дизайна.

Я не хочу комментировать этот метод для async/await ... Или это против принципа асинхронности?

Это против принципа. Если вы думаете об этом, на самом деле не имеет смысла блокировать асинхронный код. Вы хотите решить проблему асинхронности метода (что означает, что он не блокирует поток), а затем заблокировать поток на нем? Почему именно? Иногда на практике код временно заканчивается в этом состоянии во время перехода на асинхронный код, но это сложное место.

Для получения дополнительной информации см. Мою статью о async best practices, в частности «асинхронный путь».

+0

См. Пример, приведенный в обновленных деталях. Почему при вызове DEF в режиме огня и забывания подход является неправильным в этом случае. Я хочу продолжить работу с ABC (если есть что-то еще от ABC), и в то же время продолжить с DEF. Но я не хочу отмечать ABC async/wait? Это что-то не так, чего мы пытаемся достичь? –

+0

Позвольте мне перевернуть это. Вы продолжаете просить синхронизацию-асинхронность и «огонь-и-забыть», которые являются определенно антипаттерами. ** Почему ** вы «не хотите отмечать асинхронную азбуку ABC»? –

+0

На самом деле в моем веб-коде api .. код делится на несколько слоев. Сценарий похож на «Сначала мы создаем случай, и мы получаем ключ case в ответ после завершения DB Call». Это выполняется синхронно. И теперь, если ключ кейса успешно возвращен, у меня есть несколько дополнительных исправлений, которые могут быть добавлены в БД, и это не обязательно, чтобы мы дождались их сохранения и возвращаемого результата. Думаю, мы можем запустить вызов savecase в DB, ​​а затем продолжать возвращать сгенерированный ключевой ключ до View. Поэтому я не отмечал 'createcase (здесь ABC)' async –

1

«Говорят, когда метод встреча ждет ...„Он рассказывает awaitable запустить оставшуюся часть метода, когда он завершает, а затем возвращается из метода асинхронного.“»

Так давайте скажем, у вас есть метод A, который вызывает метод B. Метод B имеет ключевое слово async в своем объявлении. В методе B существует длинный вызов LongMethod, который в конечном итоге возвращает строку.

Что мы хотим здесь, для метода A не нужно ждать веков для метода LongMethod метода B для завершения. Таким образом, мы пишем в методе B:

string newVariable = await Task.Run(()=>LongMethod());

Если сам LongMethod также асинхронный, то LongMethod может возвращать только пустоту, неофициальную родовую задачу или родовую задачу. Поэтому нам нужно было бы изменить тип возврата в объявлении LongMethod на Task<string>

Итак, вернемся к нашей истории, задача LongMethod началась ... В этот момент метод A возобновляется со следующей строки кода после вызова метода B, а метод B продолжает ждать завершения LongMethod, так что теперь есть два потока. В конце концов, LongMethod завершается, и метод B заканчивается, между тем метод A продолжает работать или, возможно, даже закончен.

Надеюсь, это даст вам представление о взаимоотношениях между Async/Await и Tasks.

Теперь на вопрос 2:

Я думаю, ваш вопрос, в основном, с просьбой, если метод А в моем примере должен быть отмечен «асинхр», потому что это делает вызов метода с пометкой «асинхр», и нет, это не делает не. Также обратите внимание, что ABC() просто необходимо иметь

DoWork() Не Task.Run(() => DoWork());

ABC будет остановлен до тех пор, метод DoWork прибывает на «ждать» заявления.

Если DoWork просто нужно работать, как свою собственную задачу, и вы не хотите ABC(), чтобы остановить вообще, то просто сделать

Task.Run(() => DoWork());

Там нет никакой выгоды маркировки DoWork в асинхронном в этом случае, потому что в DoWork нет никаких утверждений о ожиданиях.

Надеюсь, это поможет, извините, если я неверно истолковал ваши вопросы!

+0

См. пример, приведенный в обновленных данных. Почему при вызове DEF в режиме огня и забывания подход является неправильным в этом случае. Я хочу продолжить работу с ABC (если есть что-то еще от ABC), и в то же время продолжить с DEF. Но я не хочу отмечать ABC async/wait? Это что-то не так, чего мы пытаемся достичь. –

+0

также вы сказали: «В этом случае нет никакой маркировки DoWork, поскольку в этом случае нет никаких ожиданий в DoWork». ... но DEF, в свою очередь, ждет еще одной продолжительной операции ExecuteStoredProcedureAsync .. так что я делаю неправильно? –

+0

Почему вы не можете просто «Задача».Run (() => DEF (SaveCaseSearchInput, AcctLst.ElementAt (0) .o_case_seq)) ' –

1

Из того, что вы сказали в своем комментарии (я предполагаю, что вам нужен результат в ABC)

Вам просто нужно написать

Task<SaveCaseSearchOutput> t = Task.Run(() =>DEF(SaveCaseSearchInput,AcctLst.ElementAt(0).o_case_seq));

в ABC, вместо текущей задачи. Выполнить вызов.

Затем на линии в ABC, когда требуется результат написать

t.Wait();
SaveCaseSearchOutput g = t.Result;

DEF должен оставаться асинхронным, но вы можете удалить заявление AWAIT в DEF.

+0

Нет. Я предполагаю, что на самом деле ожидание должно присутствовать в теле метода DEF, так как оно ждет rep.ExecuteStoredProcedureAsync для завершения. Также t. Wait() не заблокирует основной поток? Или он блокирует фоновый поток, на который вызывается задача? И в чем разница между ожиданием Task.Run() и Task.Run (() => ......)? –

+0

Если вам нужен результат из задачи в ABC, вам нужно заблокировать поток ABC, чтобы дождаться результата, выбора нет. Я только что показал вам, как свести к минимуму блокировку. Что вы хотите сделать, ожидая rep.ExecuteStoredProcedure ... для завершения? Вы хотите, чтобы вызывающий абонент продолжал работать? Ну, это уже так, потому что метод DEF работает в своей собственной задаче, поэтому вам не нужно писать «ждать». Task.Run всегда имеет параметр. –

+0

... Я понимаю, что сэр. Но ExecuteStoredProcedureAsync имеет асинхронный/ожидающий вызов в БД. Поэтому он помечен как async/wait. И, следовательно, и вызывающий. Вот почему DEF был отмечен async/wait. Если я удалю async/wait из объявления DEF ..... не будут ли все синхронные вызовы, даже если DEF работает в фоновом потоке и в конечном итоге блокирует его? –