2016-03-16 2 views
1

Я implimented (что я считаю) простым способом асинхронного в ApiController так:Debugging асинхронные ждут действий контроллера

public class CommentsController : ApiController 
{ 
    private static readonly IList<CommentModel> Comments; 

    static CommentsController() 
    { 
     // Note: Removed to abbreviate - populate comments manually here. 
    } 

    [ResponseType(typeof (IList<CommentModel>))] 
    [HttpGet] 
    public async Task<IHttpActionResult> GetAllComments() 
    { 
     return await Task.Factory.StartNew(() => 
     { 
      Thread.Sleep(10000); // Breakpoint #1 
      return Ok(Comments); // Breakpoint #2 
     }); 

     // Breakpoint #3 
    } 
} 

Примечание моих точек останова я поставил выше.

То, что я ожидал увидеть, было в №1, когда я нажал кнопку «Продолжить», чтобы поток подождал, но поток продолжался до 3-го уровня на этом этапе.

Затем, когда сон был закончен, продолжить снова и перерыв на # 2.

Однако во время отладки это кажется синхронным.

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

+0

Ps. Я нажимаю api прямо из браузера - возможно, это проблема? – shenku

ответ

1

Как будет удаляться точка останова №3? У вас есть возвращение перед ожиданием.

Итак, что произойдет, так это то, что ожидание породит конечный автомат и по завершении вашего потока просто вернет значение.

2

Точка останова 3 никогда не пострадает, и этого не должно быть.

Task Вы начинаете с Task.Factory.StartNew и будете запускать асинхронно.
Но await в основном ждет Task, чтобы завершить выполнение перед продолжением текущего метода и возвращает выполнение вызывающему. Поэтому он добавляет продолжение к данному Task.
Поскольку вы возвращаете результат Task, Breakpoint 3 никогда не будет выполнен.

Если вы хотите Breakpoint 3 выполнить после Task, вы в основном есть 2 варианта:

Либо добавить продолжение:

return await Task.Factory.StartNew(() => 
    { 
     Thread.Sleep(10000); // Breakpoint #1 
     return Ok(Comments); // Breakpoint #2 
    }).ContinueWith((Task<IHttpActionResult> t) => 
    { 
     //t.Result contains the result of the previous Task 
     return t.Result; // Breakpoint #3 
    }); 

или (проще), используют временное значение и await:

var temp = await Task.Factory.StartNew(() => 
    { 
     Thread.Sleep(10000); // Breakpoint #1 
     return Ok(Comments); // Breakpoint #2 
    }); 

    // Breakpoint #3 
    return temp; 

Для вызова async метода с в ожидании завершения выполнения, просто оставьте без него await. Итак, если вы хотите, чтобы выполнить GetAllComments параллельно в 5 раз, вы могли бы сделать это следующим образом:

for(int i = 0; i < 5; i++) 
    GetAllComments(); 
+0

Ваше последнее утверждение о выполнении параллельно является опасным. в доменах приложений Asp.Net могут быть разорваны, даже если фоновые задачи все еще запущены, если еще нет еще не выполненных запросов. Вы должны либо сохранить задачи, возвращаемые функцией «GetAllComments()», и выполнить «waitait Task.WhenAll» («чтобы выполнить gauntee они заканчиваются до того, как запрос вернется или поставит очередь каждой задачи, используя« HostingEnvironment.QueueBackgroundWorkItem »(', который не задает задачу будет завершено, но это задерживает выключение до дополнительных 90 секунд, по умолчанию позволяет завершить задачи. –

3

Однако во время отладки, кажется синхронным.

Это серийный (не синхронный), потому что ключевое слово await сообщает, что метод не должен продолжаться до завершения этой операции. Отладчик будет последовательно выполнять асинхронные методы, что может сделать их синхронными; это гораздо более естественно, чем отключение отладчика к несвязанному коду, а затем снова вернуться назад.

Мой вопрос заключается в первую очередь это действительно асинхронный

Это фальшивка асинхронный. В коде реального мира вы никогда не будете использовать Task.Factory.StarNew.

Кроме того, для приложений ASP.NET вам следует избегать отправки работы в пул потоков (StartNew, Task.Run и т. Д.). Вместо этого вы должны назвать естественно-асинхронные API.

Как отладить его, чтобы проверить или иным образом провести модульные тесты?

Вы можете вызвать метод, убедитесь, что задача еще не завершена, а затем ждите ее. Обратите внимание, что во избежание условий гонки вы должны отключить любую асинхронную службу, которую использует ваш контроллер.

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