使用async / await在WebApi中进行扇出计算

时间:2015-09-04 17:15:30

标签: c# asp.net-web-api async-await

我说过一个名为:

的界面
interface IExecutor {
   String Name { get; }
   Task<int> Execute();
}

它的两个实现(细节是无关紧要的,您可以假设方法标记为异步并按预期工作)。每个实现需要2-3秒才能运行,并且IExecutor将会有2到5个实现

我有一个控制器需要运行所有执行程序并将结果作为ExecutorResult对象返回。 ExecutorResult的地方是:

class ExecutorResult {
    int Result; // assume usual get n set
    String ExecutorName;
}

理想情况下,这应该以扇出方式进行。

我想到了以下方法:

List<Task<int>> tasks = new List<Task<int>>();
foreach(var executor in executors) {
    tasks.Add(executor.Execute());
}

var results = Task.WhenAll(tasks);

我对这种方法的问题是我不确定这是否是ASP WebAPI应用程序中的最佳实践。另外 - 鉴于我想返回Result对象 - 其中Result需要执行者的名称,而执行上述解决方案的int结果在for循环之外不起作用我不再能够访问每个对象的Name属性执行程序。

那么这种方法的最佳实践是什么(再次 - 给定一个Web Api应用程序而不是控制台应用程序)

3 个答案:

答案 0 :(得分:2)

您已经拥有的是最佳实践。你正在做的是异步并发,最好用Task.WhenAll完成。

请注意代码:

List<Task<int>> tasks = new List<Task<int>>();
foreach(var executor in executors) {
  tasks.Add(executor.Execute());
}
var results = Task.WhenAll(tasks);

可以简化为:

var results = Task.WhenAll(executors.Select(e => e.Execute()));

尽管有无数个例​​子使用List<Task>,但实际上你并没有明确地建立一个。

答案 1 :(得分:1)

如果我理解正确,你会找到这样的东西:

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

或者,按照Stephen Clearly的建议:

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

答案 2 :(得分:1)

这对我有用:

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