using TaskFactory.StartNew, lik..." /> using TaskFactory.StartNew, lik..." /> using TaskFactory.StartNew, lik..."/>

How can I use TaskFactory.StartNew<Task<Result>> with async methods?

1.6k Views Asked by At

I have an async Func<> where I "await" for a async method. I want to make a lot of parallel calls to that Func<> using TaskFactory.StartNew, like the below code, but I get the followin error:

error converting 'System.Threading.Tasks.Task<System.Threading.Tasks.Task<Result>>' to 'System.Threading.Tasks.Task<Result>'

How can I have a parallel calls for a async method?

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

1

There are 1 best solutions below

2
On BEST ANSWER

Assuming you are using a taskFactory.StartNew( instead of Task.Run( because you have a special configured TaskFactory you need to unwrap the result of the StartNew, which will be a Task<Task<Result>>. The easiest solution is use the .Unwrap() extension method to unwrap the nested task.

You also should replace the .ForEach(r=> sending.Add( with a .Select(r => statement to reduce the number of times the list is iterated over. If you are returning a IEnumerable<Result> instead of a List<Result> you can remove your final .ToList() too.

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

If you are not using a special task factory your code can be simplified to

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