如何将 TaskFactory.StartNew<Task<Result>> 与异步方法一起使用?

Jos*_*nso 1 c# multithreading asynchronous taskfactory

我有一个 async Func<> ,我在其中“等待”异步方法。我想使用 TaskFactory.StartNew 对 Func<> 进行大量并行调用,如下面的代码,但出现以下错误:

转换'System.Threading.Tasks.Task<System.Threading.Tasks.Task<Result>>'为错误'System.Threading.Tasks.Task<Result>'

如何并行调用异步方法?

Func<object, Task<Result>> action = async (object m) =>
{
    try
    {
        return await Send<Message, Result>(m as Message);
    }
    catch (Exception exc)
    {
        Result result = new Result();
        (result as ResponseBaseDto).Success = false;
        (result as ResponseBaseDto).ErrorList = new List<Entities.Common.ErrorDto>()
        {
            new Entities.Common.ErrorDto{ Code = 9999, Message = exc.Message }
        };
        return result;
    }
};

// Error on request.ForEach
request.ForEach(r => sending.Add(taskFactory.StartNew<Task<Result>>(action, r)));
var tareas = sending.ToArray();
await Task.WhenAll(tareas);
return tareas.Select(s => s.Result).ToList();
Run Code Online (Sandbox Code Playgroud)

Sco*_*ain 7

假设您使用 ataskFactory.StartNew(而不是Task.Run(因为您有特殊配置,TaskFactory您需要解开 StartNew 的结果,这将是一个Task<Task<Result>>. 最简单的解决方案是使用.Unwrap()扩展方法来解开嵌套任务。

您还应该将 替换.ForEach(r=> sending.Add(.Select(r =>语句以减少迭代列表的次数。如果您返回的是 aIEnumerable<Result>而不是 a,List<Result>您也可以删除最后的.ToList()

var tareas = request.Select(r => taskFactory.StartNew<Task<Result>>(action, r).Unwrap());
var results = await Task.WhenAll(tareas); //results is a `Result[]`
return results.ToList(); // you may not need this .ToList().
Run Code Online (Sandbox Code Playgroud)

如果您不使用特殊的任务工厂,您的代码可以简化为

var tareas = request.Select(r => Task.Run(() => action(r)));
var results = await Task.WhenAll(tareas); //results is a `Result[]`
return results.ToList(); // you may not need this .ToList().
Run Code Online (Sandbox Code Playgroud)