Task.WhenAny仅解决最快的任务

时间:2018-11-27 03:25:03

标签: c# async-await task-parallel-library

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

我认为我应该使用Task.WhenAny,但似乎并没有正确实现该实现。下面的GoAsync实现不返回任何记录,它在等待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);

请注意,我深陷于例程中,我需要并行运行这些任务才能获得竞争结果。该例行程序是 私有静态void DoVariousCalucualtions(){}

1 个答案:

答案 0 :(得分:1)

您无需创建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;,将最终陷入僵局,这是您已经经历的行为...