简体   繁体   English

异步/等待-我是否正确并行运行这些方法?

[英]async / await - am I correctly running these methods in parallel?

I have an abstract class called VehicleInfoFetcher which returns information asynchronously from a WebClient via this method: 我有一个名为VehicleInfoFetcher的抽象类,它通过以下方法从WebClient异步返回信息:

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

I'd like to combine the results of two separate instances of this class, running each in parallel before combining the results. 我想合并该类的两个单独实例的结果,并在合并结果之前并行运行每个实例。 This is done within a third class, CombinedVehicleInfoFetcher (also itself a subclass of VehicleInfoFetcher ) 这是在第三类CombinedVehicleInfoFetcher (本身也是VehicleInfoFetcher的子类)中完成的

Here's my code - but I'm not quite convinced that it's running the tasks in parallel; 这是我的代码-但我不太相信它是并行运行任务的; am I doing it right? 我做对了吗? Could it be optimized? 可以优化吗?

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

    }

Edit 编辑

Some very helpful answers, here is a re-written example to aid discussion with usr below: 一些非常有用的答案,这是一个重写的示例,以帮助下面的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)  );
        }
    }

Almost all tasks start out already started. 几乎所有任务开始时都已经开始。 Probably, whatever fetcher.getVehicleInfo returns is already started. 可能任何fetcher.getVehicleInfo返回的内容fetcher.getVehicleInfo启动。 So you can remove: 因此,您可以删除:

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

Task.WhenAll is faster and has better error behavior (you want all exceptions to be propagated, not just the first you happen to stumble upon). Task.WhenAll更快并且具有更好的错误行为(您希望传播所有异常,而不仅仅是偶然遇到的第一个异常)。

Also, await does not start a task. 此外,等待不会启动任务。 It waits for completion. 等待完成。 You have to arrange for the tasks to be started separately, but as I said, almost all tasks are already started when you get them. 您必须安排要分别启动的任务,但是正如我所说,几乎所有任务都已经在您启动时启动。 This is best-practice as well. 这也是最佳做法。


To help our discussion in the comments: 为了帮助我们在评论中进行讨论:

 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. Does not "run" when returned from the method. 从方法返回时不“运行”。 Must be started. 必须开始。 Bad practice. 不好的做法。
  2. Runs when returned. 返回时运行。 Does not matter what you do with it, it is already running. 不管您做什么,它已经在运行。 Not necessary to add it to a list or store it somewhere. 无需将其添加到列表或将其存储在某处。
  3. Already runs like (2). 已经像(2)一样运行。
  4. The notion of running does not make sense here. 运行的概念在这里没有意义。 This task will never complete although it cannot be explicitly started. 尽管无法明确启动此任务,但它将永远不会完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM