如何在运行代码之前等待所有任务完成

时间:2014-04-09 12:01:39

标签: asp.net-mvc multithreading async-await c#-5.0

我正在尝试编写多线程搜索,然后在任务完成后显示所有结果,但目前我还不了解如何在所有任务完成后处理结果

我的代码如下:

    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;
    }

_searchResultsList<SearchResult>

的位置

我的理解是它会同时进行两种等待,然后将产品添加到搜索结果中。但是,当我在我的控制器中调用它时:

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

        return View(helper);
    }

在搜索完成之前显示页面,因此没有显示任何结果。如何在显示页面之前等待结果完成?

我已经查看Tasks.Wait,但不知道如何将其应用于上述内容,因为它需要一系列任务

    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));
    }

5 个答案:

答案 0 :(得分:13)

每次在ASP.NET控制器中调用Factory.StartNewTask.Run时,都会从ThreadPool获取一个帖子。该线程可以以其他方式提供另一个传入的HTTP请求。因此,您的网络应用可扩展性确实受到了损害。这可能是一个严重的问题,具体取决于您的Web应用程序预计会收到多少并发HTTP请求。

你还好吗?如果是这样,代码可能如下所示:

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);
}

注意我已为async voidasync Task更改为DoSearchAsync,并将控制器方法设为async,因此返回Task<ActionResult>

答案 1 :(得分:1)

  

我的理解是,它将同时进行两项等待

这是不正确的皮特。 await意味着它将暂停当前方法的执行,直到被调用的Async方法完成为止。因此,您的2次搜索将无法并行运行。

有关说明,请参阅the first line of the MSDN documentation ....

  

await运算符应用于异步方法中的任务,以暂停方法的执行,直到等待的任务完成。

您应该使用Task.WhenAll等待两个搜索完成。由于WhenAll支持返回Task<T>并且两个异步搜索都返回List<SearchResult>,您可以将两个搜索的结果组合在一起,并在一个语句中等待它们......

    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>[]

为了完整性,值得注意的是allResults将包含2个结果集。它不会在2套上执行联合。

可以找到LinqPad的完整工作示例here on GitHub

答案 2 :(得分:0)

您可以使用任务工厂,然后对生成的任务调用wait:

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

答案 3 :(得分:0)

你可以让它在显示页面之前等待结果完成,方法是让你的函数不要异步。

或者,如果您想要异步,可以移动搜索功能,以便在加载页面时触发的AJAX调用调用

答案 4 :(得分:0)

您需要等待该功能完成。为了做到这一点,首先让它返回一个任务:

private async Task DoSearchAsync()

等待它:

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

    return View(helper);
}

有关详细信息,请参阅http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4