2016-03-07 2 views
1

Я просто наткнулся кодирование параллелизма на asp.net и нашел там 2 способа, чтобы вызвать метод асинхронного в методе Page_Loadв ASP.NET последовательность выполнения асинхронных задач

  1. RegisterAsyncTask (новый PageAsyncTask (DoSthAsync())) ;
  2. Ожидание DoSthAsync();

Однако они имеют разные результаты работы. Для случая 1 код сразу после RegisterAsyncTask будет запускаться непосредственно перед любым кодом в DoSthAsync(). Пока код после ждет будет запущен по завершении DoSthAsync().

Например:

//protected async void Page_Load(object sender, EventArgs e) 
protected void Page_Load(object sender, EventArgs e) 
{  
    Response.Write("Start</br>"); 
    Response.Flush(); 
    RegisterAsyncTask(new PageAsyncTask(DoSthAsync())); 
    //await DoSthAsync(); 
    Response.Write("End</br>"); 
    Response.Flush(); 
} 

public async Task LoadSomeData() 
{ 
    await Task.Delay(1000); 
    Response.Write("Do Sth Async</br>"); 
    Response.Flush(); 
} 

Этот фрагмент кода будет генерировать следующий результат:

Start 
End 
Do Sth Async *(after 1 second delay)* 

В то время как я раскомментировать ждут DoSthAsync() код и комментарии RegisterAsyncTask, следующий результат будет показано на рисунке.

Start 
Do Sth Async *(after 1 second delay)* 
End 

В статье Рик Андерсон Using Asynchronous Methods in ASP.NET 4.5, он предложил использовать RegisterAsyncTask даст лучший контроль над исполнением кода. Тем не менее, это дает неожиданный результат, который я ищу в ожидании в page_load, будет генерировать идентичный, поскольку я пытаюсь использовать аналогичную последовательность кода в программе Windows.

В своей статье у Рика также есть код запуска секундомера перед запуском GetPWGsrvAsync() после того, как весь асинхронный код завершен, показывая, как долго выполняется код. Он показывает, прошедшее время составляет 0,872 с в крышке экрана. Поэтому ожидается, что секундомер будет остановлен после того, как весь предыдущий код, включая все в асинхронном методе, будет завершен.

....... 
Stopwatch stopWatch = new Stopwatch(); 
stopWatch.Start(); 
RegisterAsyncTask(new PageAsyncTask(DoSthAsync())); 
//await DoSthAsync(); 
stopWatch.Stop(); 
Response.Write(String.Format("Elapsed time:{0}",stopWatch.Elapsed.Milliseconds/1000.0)); 
Response.Write("</br>"); 
Response.Flush(); 
....... 

В то время как я следую его таким же образом, как фрагмент кода выше, у меня есть другой результат в любом RegisterAsyncTask или ждут DoSthAsync(). Хотя Истекшее время отображаются в разных положениях, они оба дают мне очень короткое истекшее время около 0,010 или 10 + мс, и считается, что секундомер остановлен очень быстро после асинхронной функции DoSthAsync() уволен. Фактически, аналогичный результат в оконной программе тоже очень скоро прекратился.

После подробного описания проблемы я хотел бы спросить, какой способ асинхронного кодирования иметь лучший контроль и шаблон кода. Между тем, как я мог ожидать результата секундомера, чтобы дать мне точное время прохождения кода.

ответ

1

Страница async задачи были вокруг, задолго до async-await.

Задачи async для страницы - выполнение асинхронных задач (не обязательно Task s) в жизненном цикле запроса.

async-await имеет асинхронные методы с асинхронными операциями.

Если вы используете async-await в Page_Load, потому что это void -returning метод, среда выполнения не имеет никакого способа знать, что метод является асинхронным, и если его асинхронная работа выполнена или нет.

Посмотрите на the documentation for PageAsyncTask и посмотрите, что лучше всего соответствует вашим потребностям. Но вы должны серьезно рассмотреть асинхронные задачи страницы.

+0

Я также полагаю, что вы должны прочитать следующую статью Скотта Hanselmann по этой теме: http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx –

+0

@ManuelZelenka Я прочитал эту статью, тоже, но у него есть нет никакого упоминания о различии между RegisterAsyncTask и ждать. он просто упомянул «Использование async с пустотами не является стабильным или надежным. Однако все, что вам нужно сделать, это вызвать страницу. RegisterAyncTask - это не проблема, и вы будете в более гибком месте». Это то же самое, что я упоминал в статье Рика. И его пример просто имеет одно действие в Page_Load. – Donald

+0

Да, я использую RegisterAsyncTask давно, а asp.net 2.0. Это просто немного сложно, когда он используется с новым ожиданием async. Последовательность выполнения кода является неожиданной.В статье Рика «Методы, связанные с RegisterAsyncTask, будут выполняться сразу после PreRender». Итак, образец, который я написал выше, означает, что DoSthAsync() фактически не запущен в Page_Load? – Donald

1

Прежде всего: ваш Stopwatch возвращает такие смехотворно короткие промежутки времени в обоих случаях, так как вы используете неправильное свойство. stopWatch.Elapsed.Milliseconds просто вернет вам количество миллисекунд за последнюю секунду измеренного интервала. То, что вы хотели, это stopWatch.ElapsedMilliseconds, так как это вернет общее количество миллисекунд, прошедшее во время измерения. И это предоставит вам большие различия между двумя используемыми методами.

await DoSthAsync(); будет иметь время выполнения чуть более одной секунды. Это связано с тем, что ключевое слово await в основном означает: дождитесь завершения асинхронной операции и только после этого выполните код ниже. Это гарантирует вам, что по крайней мере в этом контексте код запускается в синхронном стиле, но выполнение длительной операции запланировано на поток ThreadPool. Это фактически делает то, что вы хотите, но все еще имеет недостаток использования async/await в методе возврата void, который не является незаконным, но я бы воздержался от него. Вы можете прочитать все на своих минусах here.

Второй подход, который использует RegisterAsyncTask и PageAsyncTask, будет иметь время выполнения где-то ниже 1 секунды. Это связано с тем, что он просто регистрирует задачу для выполнения и сразу возвращается для обработки кода ниже. Поскольку ваш код записан в событии Page_Load, выполнение вашей длительной операции начнется автоматически только после завершения события PreRenderComplete. Но вы можете запустить выполнение своей задачи вручную с помощью Page.ExecuteRegisteredAsyncTasks();. Но обратите внимание: это также не будет ждать завершения вашей задачи и просто начнет выполнение раньше.

В основном у вас есть два варианта осталось, чтобы получить результат, который вы хотите:

  1. Используйте свой первый подход и жить с минусов.
  2. Рефакторинг вашего кода, чтобы вы могли использовать второй подход, используя другой конструктор PageAsyncTask, который включает EventHandlers. Вы можете использовать эти EventHandlers для выполнения кода, который должен запускаться после завершения асинхронной задачи. Вы можете найти хороший пример для этого подхода here.

Что вы будете делать с этой информацией зависит от вас. Напомним, что я настоятельно рекомендую использовать вариант 2 для вас.

Смежные вопросы