1

我有一个名为的抽象类,它通过此方法VehicleInfoFetcher从 a 异步返回信息: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;
        }

    }

编辑

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

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

1 回答 1

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. 跑步的概念在这里没有意义。尽管无法显式启动此任务,但它永远不会完成。
于 2013-07-26T13:31:48.207 回答