async / await - 我是否正确地并行运行这些方法?

时间:2013-07-26 13:26:01

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

我有一个名为VehicleInfoFetcher的抽象类,它通过此方法从WebClient异步返回信息:

public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID);

我想结合这个类的两个独立实例的结果,在组合结果之前并行运行每个实例。这是在第三类CombinedVehicleInfoFetcher(也是VehicleInfoFetcher的子类)中完成的

这是我的代码 - 但我不太相信它并行运行任务;我做得对吗?可以优化吗?

 public class CombinedVehicleInfoFetcher : VehicleInfoFetcher
    {
        public HashSet<VehicleInfoFetcher> VehicleInfoFetchers { get; set; }

        public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID)
        {
            // Create a list of parallel tasks to run
            var resultTasks = new List<Task<DTOrealtimeinfo>>();
            foreach (VehicleInfoFetcher fetcher in VehicleInfoFetchers)
                resultTasks.Add(fetcher.getVehicleInfo(stopID, stopID2, timePointLocal));

            // run each task
            foreach (var task in resultTasks)
                await task;

            // Wait for all the results to come in
            await Task.WhenAll(resultTasks.ToArray());

            // combine the results
            var allRealtimeResults = new List<DTOrealtimeinfo>( resultTasks.Select(t => t.Result)  );
            return combineTaskResults(allRealtimeResults);
        }

        DTOrealtimeinfo combineTaskResults(List<DTOrealtimeinfo> realtimeResults)
        {
             // ...


            return rtInfoOutput;
        }

    }

修改

一些非常有用的答案,这是一个重写的例子,以帮助下面与我们讨论:

       public override async Task<object> combineResults()
        {
            // Create a list of parallel tasks to run
            var resultTasks= new List<object>();
            foreach (AnotherClass cls in this.OtherClasses)
                resultTasks.Add(cls.getResults() );

            // Point A - have the cls.getResults() methods been called yet?

            // Wait for all the results to come in
            await Task.WhenAll(resultTasks.ToArray());

            // combine the results
             return new List<object>( resultTasks.Select(t => t.Result)  );
        }
    }

1 个答案:

答案 0 :(得分:2)

几乎所有任务都已经开始了。可能,任何fetcher.getVehicleInfo返回已经开始。所以你可以删除:

        // run each task
        foreach (var task in resultTasks)
            await task;

Task.WhenAll更快,并且具有更好的错误行为(您希望传播所有异常,而不仅仅是您偶然遇到的第一个异常)。

此外,await不会启动任务。它等待完成。你必须安排单独启动任务,但正如我所说的,几乎所有任务都已经启动了。这也是最好的做法。

<小时/> 为了帮助我们在评论中进行讨论:

Task Test1() { return new Task(() => {}); }
Task Test2() { return Task.Factory.StartNew(() => {}); }
Task Test3() { return new FileStream("").ReadAsync(...); }
Task Test4() { return new TaskCompletionSource<object>().Task; }
  1. 从方法返回时不“运行”。必须开始。不好的做法。
  2. 退回时运行。无论你用它做什么,它已经在运行了。没有必要将它添加到列表或存储在某个地方。
  3. 已经像(2)一样运行。
  4. 跑步的概念在这里没有意义。尽管无法明确启动,但此任务永远不会完成。