首页 > 解决方案 > Task.WhenAny 只抓取解决最快的任务

问题描述

我有两个异步方法都返回一个列表。他们都以不同的方式搜索记录,我需要他们都并行运行,我只关心首先完成的任务。如果可能,应取消另一个。

我想我应该使用 Task.WhenAny 但似乎没有得到正确的实现。下面的 GoAsync 实现不返回任何记录,它在 await Task.WhenAny(taskList) 行跳出例程(无错误)。我没有得到结果,等等。我怎样才能得到结果?我这样做对吗?

public static async void GoAsync(SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {
            var taskList = new List<Task>();

            taskList.Add(new Task(async () => await SearchRoutine1Async(search, cancellationToken)));
            taskList.Add(new Task(async () => await SearchRoutine2Async( search, cancellationToken)));

            Task completedTask = await Task.WhenAny(taskList);
        }

异步例程是这样的:

 public static async Task<List<SearchModel>> SearchRoutine1Async( SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {
            using (DBContext db = new DBContext)
            {
                var searchModels= await db.SearchModel
                    .Where(sm => sm.subKey1 = search.subKey1)
                    .ToListAsync(cancellationToken)
                    ; 

                return searchModels;
            }
        }

当我尝试单独运行这些任务时,例如这样做:它工作正常。

var callTask = Task.Run(() => SearchRoutine1Async(search));
callTask.Wait();
var list1 = callTask.Result;

var callTask2 = Task.Run(() => SearchRoutine2Async(search));
callTask2.Wait();
var list2 = callTask.Result;

[更新]:我已将我的 GoAsync 更改为:根据以下答案之一:(但它仍然无法正常工作)

public static async Task<List<SearchModel>> GoAsync(SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {

            var taskList = new List<Task<List<SearchModel>>>
            {                    
                SearchRoutine1Async(search, cancellationToken),
                SearchRoutine2Async(search, cancellationToken)
            };

            Task<List<SearchModel>> completedTask = await Task.WhenAny(taskList);

            return completedTask.Result;
        }

我从 SYNCHRONOUS 例程中调用例程,如下所示:

var result = GoAsync(search);

请注意,我深陷于需要并行运行这些任务以获得竞争结果的例程中。该例程作为 private static void DoVariousCalucualtions() {} 的签名

标签: c#async-awaittask-parallel-library

解决方案


您不需要创建new Task,异步方法将返回一个任务。

public static async Task GoAsync(
    SearchContract search,
    CancellationToken cancellationToken = default(CancellationToken))
{
    var taskList = new List<Task<List<SearchModel>>>
    {
        SearchRoutine1Async(search, cancellationToken),
        SearchRoutine2Async( search, cancellationToken)
    };

    Task<List<SearchModel>> completedTask = await Task.WhenAny(taskList);
    // use competedTask.Result here (safe as you know task is completed)
}

问题更新后:

要获得结果,您需要等待功能完成。

var result = await GoAsync();

但是您提到此调用位于带有void签名的同步函数的深处,并且您没有使用 ASP.Net Core。这意味着您需要从控制器操作开始使整个“方法管道”异步。如果你会使用GoAsync().Result;你最终会陷入僵局,你已经经历过的行为......


推荐阅读