How to wait until all tasks are finished before running code

风格不统一 提交于 2019-11-30 22:48:31

Every time you call Factory.StartNew or Task.Run inside an ASP.NET controller, you grab a thread from ThreadPool. That thread could be otherwise serving another incoming HTTP request. So, your're really hurting your web app scalability. This may be a serious issue, depending on how many concurrent HTTP requests your web app is expected to receive.

Are you OK with that? If so, the code could look like this:

private async Task DoSearchAsync()
{
    var productResults = SearchProductsAsync(CoreCache.AllProducts);
    var brochureResults = SearchBrochuresAsync(CoreCache.AllBrochures);

    await Task.WhenAll(productResults, brochureResults);

    _searchResults.AddRange(productResults.Result); 
    _searchResults.AddRange(brochureResultsbrochure.Results);

    ResultsCount = _searchResults.Count;
}

public async Task<ActionResult> Index(string searchText)
{
    SearchHelper helper = new SearchHelper(searchText);

    await helper.DoSearchAsync();

    return View(helper);
}

Note I changed async void to async Task for DoSearchAsync, and made your controller method async, so it returns Task<ActionResult>.

My understanding is that it will do both of the awaits simultaneously

This is not correct Pete. The await means that it will pause execution of the current method until such time that the Async method being called completes. So your 2 searches will not run in Parallel.

For clarification, see the first line of the MSDN documentation....

The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes.

You should use Task.WhenAll to wait for both searches to complete. As WhenAll supports returning Task<T> and both of your Async searches return a List<SearchResult> you can combine the results of both searches and await them both in one statement...

    var searchProducts = Task.Factory.StartNew(() => GetProducts(CoreCache.AllProducts));
    var searchBrochure = Task.Factory.StartNew(() => GetBrochures(CoreCache.AllBrochures));
    var allResults = await Task.WhenAll(new [] { searchProducts, searchBrochure });
    //allResults is List<SearchResult>[]

For completeness, its worth noting that allResults will contain 2 result sets. It does not perform a union on the 2 sets.

A complete working example for LinqPad can be found here on GitHub

You can use a task factory, then call wait on the resulting task:

Task taskA = Task.Factory.StartNew(() => DoSomeWork(10000000));
        taskA.Wait();
        Console.WriteLine("taskA has completed.");

http://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx

You can make it wait for the results to finish before displaying the page by making your function NOT be async.

Or if you want async you could move the search functions to be called by an AJAX call triggered when your page is loaded

You need to wait for the function to complete. In order to do that, first make it return a task:

private async Task DoSearchAsync()

then await it:

public async Task<ActionResult> Index(string searchText)
{
    SearchHelper helper = new SearchHelper(searchText);
    await helper.DoSearchAsync();

    return View(helper);
}

For more information, see http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!