I have say an interface called:
interface IExecutor {
String Name { get; }
Task<int> Execute();
}
And two implementations of it (details are irrelevant and you can assume methods are marked with async and work as expected). Each implementation takes between 2-3 seconds to run and there will ever be between 2 and 5 implementations of IExecutor
I have a controller that needs to run all executors and return the results in as ExecutorResult objects. Where ExecutorResult is:
class ExecutorResult {
int Result; // assume usual get n set
String ExecutorName;
}
Ideally this should happen in a Fan-Out approach.
I have thought of the following approaches:
List<Task<int>> tasks = new List<Task<int>>();
foreach(var executor in executors) {
tasks.Add(executor.Execute());
}
var results = Task.WhenAll(tasks);
The problem I have with this approach is that I m not sure if this is best practice in an ASP WebAPI application. Also - given I would like to return Result objects - where Result needs an the name of the executor and the int result from Execute the above solution doesn't work as outside of the for loop I no longer have access to the Name property of each executor.
So what is the best practice for this approach (again - given a Web Api application and not a Console app)
What you have already is a best practice. What you're doing is asynchronous concurrency , which is best done with Task.WhenAll
.
Note that the code:
List<Task<int>> tasks = new List<Task<int>>();
foreach(var executor in executors) {
tasks.Add(executor.Execute());
}
var results = Task.WhenAll(tasks);
can be simplified to:
var results = Task.WhenAll(executors.Select(e => e.Execute()));
In spite of the countless examples using List<Task>
, you don't actually have to build one up explicitly.
If I understood it correctly, you're looking for somethng like this:
var tasks = new List<Task<ExecutorResult>>();
foreach (var executor in executors)
{
tasks.Add(((Func<IExecutor, Task<ExecutorResult>>)(
async (e) => new ExecutorResult
{
ExecutorName = e.Name,
Result = await e.Execute()
}))(executor));
}
var results = Task.WhenAll(tasks);
OR, following Stephen Clearly suggestion:
var results = Task.WhenAll(
from executor in executors
select ((Func<IExecutor, Task<ExecutorResult>>)(
async (e) => new ExecutorResult
{
ExecutorName = e.Name,
Result = await e.Execute()
}))(executor))
);
This worked for me:
public class Executor : IExecutor
{
public String Name { get; set;}
public async Task<int> Execute()
{
Console.WriteLine("Executing " + Name);
await Task.Delay(3000);
Console.WriteLine("Finished Executing " + Name);
return 0;
}
}
public async Task<ExecutorResult> Execute(IExecutor executor)
{
return new ExecutorResult { ExecutorName = executor.Name,
Result = await executor.Execute() };
}
public async Task MainAsync()
{
var executors = new List<IExecutor>
{
new Executor { Name = "Executor1" },
new Executor { Name = "Executor2" },
new Executor { Name = "Executor3" }
};
List<Task<ExecutorResult>> tasks = new List<Task<ExecutorResult>>();
foreach(var executor in executors)
{
tasks.Add(Execute(executor));
}
var results = await Task.WhenAll(tasks);
}
void Main()
{
MainAsync().Wait();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.