c# - TPL 控制流问题

标签 c# async-await task-parallel-library task

我有三个类(class):

BargeGrouper实现 IBargeGrouper 的类并且有 Group(IEnumerable<Barge> ungrouped)方法。

BargeGroupMap实现 IBargeGroupShow 的类并且有 Show(IEnumerable<BargeGroup>方法。

如果这些都属于我调用的类:GroupingModule它是 Run() .

问题是当我调用 Group(ungrouped); 时然后想Show(bargeGroups);我得到了 IndexOutOfRange Show(bargeGroups); 中的异常因为IEnumerable我传递给它作为参数有 Count属性比其中的实际元素多得多。我发现分组集合从 Group 返回为空大多数时候尽管我使用 ContinueWithBargeGroup 填充该集合元素。

Group BargeGrouper的方法|

public IEnumerable<BargeGroup> Group(IEnumerable<Barge> ungroupedBarges)
{
    List<BargeGroup> bargeGroups = new List<BargeGroup>();
    Int32 groupNumber = 0;

    var riverBarges = from barge in ungroupedBarges
                      where barge != null && !String.IsNullOrEmpty(String.Intern(barge.River))
                      let river = String.Intern(barge.River)
                      orderby river, barge.MileMarker ascending
                      group barge by river into barges
                      select barges.AsEnumerable();

    foreach (IEnumerable<Barge> barges in riverBarges)
    {
        Task.Run(() => ResolveRiver(barges, ref groupNumber)).ContinueWith(t=>
        {
            IEnumerable<BargeGroup> riverGroups = t.Result;
            bargeGroups.AddRange(riverGroups);
        });
    }

    return bargeGroups;
}

ShowBargeGroups :

public void ShowBargeGroups(IEnumerable<BargeGroup> bargeGroups)
{
    Console.WriteLine("Barge groups :");
    if (bargeGroups != null)
    {
        foreach (var group in bargeGroups.Where(b => b != null))
        {
            var title = String.Format("{0}\n\t | {1} \t\t | {2} \t | {3} \t|", group.Id, "Id", "River", "MileMarker");
            Console.WriteLine(title);
            foreach (var barge in group.Barges)
            {
                var caption = String.Format("\t | {0}\t | {1} \t | {2} \t|", barge.Id, barge.River, barge.MileMarker);
                Console.WriteLine(caption);
            }
        }
    }
}

并在 GroupingModule 中使用:.

var groupBarges = bargeGrouper.Group(barges);

bargeGroupShow.ShowBargeGroups(groupBarges);

我该怎么做才能解决这个问题?

最佳答案

当使用 Task.Run 时,它返回一个 Task 而不是异步等待它,下一行的执行将立即发生,它不会等待委托(delegate)通过完成。

解决此问题的一种方法是并行发出对 ResolveRiver 的调用并异步等待多个任务完成:

public Task<IEnumerable<BargeGroup>> GroupAsync(IEnumerable<Barge> ungroupedBarges)
{
    // Do the grouping

    var riverTasks = riverBarges.Select(barges => 
                                        Task.Run(ResolveRiver(barges, ref groupNumber)));

    var result = await Task.WhenAll(riverTasks);
    bargeGroups.AddRange(result.Result.SelectMany(x => x));
    return bargeGroups;
}

然后像这样消费它:

public async Task FooAsync()
{
    var barges = await GroupAsync(ungroupedBarges);
    ShowBargeGroups(barges);
}

请注意,我会小心地并行传递和调用 ref 参数,这并不安全。如果您可以从等式中删除 groupNumber,请这样做。

关于c# - TPL 控制流问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33890204/

相关文章:

c# - Visual Studio 项目文件格式 - "new one"有实际名称吗?

c# - xml注释中的回车或换行

c# - 如何使用 Task<List<T>> 从多个方法填充 List<T>?

vb.net - 我需要担心创建的任务数量吗?

c# - 每个 C# 控制台应用程序打印 "The system cannot find the path specified"

c# - 无法理解从此 Entity Framework 查询生成的 SQL

c# - 我无法理解 await/async 究竟是如何工作的

c# - 异步/等待问题 - 等待的操作结束会发生什么?

c# - C# 中的任务并行库和 PLINQ 替代方案