我有三个类(class):
BargeGrouper
实现 IBargeGrouper
的类并且有 Group(IEnumerable<Barge> ungrouped)
方法。
BargeGroupMap
实现 IBargeGroupShow
的类并且有 Show(IEnumerable<BargeGroup>
方法。
如果这些都属于我调用的类:GroupingModule
它是 Run()
.
问题是当我调用 Group(ungrouped);
时然后想Show(bargeGroups);
我得到了 IndexOutOfRange
Show(bargeGroups);
中的异常因为IEnumerable
我传递给它作为参数有 Count
属性比其中的实际元素多得多。我发现分组集合从 Group
返回为空大多数时候尽管我使用 ContinueWith
用 BargeGroup
填充该集合元素。
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/