Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait until all tasks are finished before running code

I am trying to write a multi threading search and then display all the results once the tasks have finished running but currently I don't understand how to process the results once all the tasks are complete

My code is as follows:

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

        _searchResults.AddRange(productResults); 
        _searchResults.AddRange(brochureResults);

        ResultsCount = _searchResults.Count;
    }

Where _searchResults is a List<SearchResult>

My understanding is that it will do both of the awaits simultaneously and then add the products to the search results. However when I call this in my controller:

    public ActionResult Index(string searchText)
    {
        SearchHelper helper = new SearchHelper(searchText);
        helper.DoSearchAsync();

        return View(helper);
    }

It is displaying the page before the searches are complete so no results are showing up. How do I make it wait for the results to finish before showing the page?

I've had a look into Tasks.Wait but don't know how to apply it to the above as it expects an array of tasks

    private Task<List<SearchResult>> SearchProductsAsync(IEnumerable<Product> products)
    {
        return Task<List<SearchResult>>.Factory.StartNew(() => GetProducts(products));
    }

    private Task<List<SearchResult>> SearchBrochuresAsync(IEnumerable<Assets> brochures)
    {
        return Task<List<SearchResult>>.Factory.StartNew(() => GetBrochures(brochures));
    }
like image 801
Pete Avatar asked Dec 09 '22 08:12

Pete


1 Answers

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>.

like image 139
noseratio Avatar answered Dec 10 '22 21:12

noseratio