我有三个班级:
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);
def team_member_params
params.require(:team_member).permit(:name, :id_steam, :color, :avatar, :avatar_color, :description, :rank_cs, :rank_lol, :role_cs, :role_lol, team_members_games: [ :id, :name_game])
end
我该怎么做才能解决这个问题?
答案 0 :(得分:2)
当使用Task.Run
,它返回Task
而没有异步等待它时,下一行的执行将立即发生,它不会等待传递完成的委托。
解决此问题的一种方法是并行发出对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
,请执行此操作。
答案 1 :(得分:1)
Task.Run不会马上完成它的工作。所以至少你的代码中存在竞争条件。试试这样:
public async Task<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)
{
var riverGroups = await Task.Run(() => ResolveRiver(barges, ref groupNumber));
bargeGroups.AddRange(riverGroups);
}
return bargeGroups;
}
答案 2 :(得分:0)
无法保证当您从Group
方法返回时,Task
已完成处理bargeGroups
列表。我怀疑你的ResolveRiver
方法可能需要一些时间。
在从Group
返回枚举之前,您需要等待执行处理的任务结束。我建议为Group
提出Task
异步和等待:
public async Task<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)
{
await Task.Run(() => ResolveRiver(barges, ref groupNumber)).ContinueWith(t=>
{
IEnumerable<BargeGroup> riverGroups = t.Result;
bargeGroups.AddRange(riverGroups);
});
}
return bargeGroups;
}
确实,正确的方法是让ResolveRiver
异步并等待它。然后,您可以摆脱用于与bargeGroups
通信的List
Task
。
如果您不想采用 async / await 方式,可能只需.Wait()
Task
。
答案 3 :(得分:0)
你的代码中的Task.Run创建了另一个等待的东西,很可能在你的函数返回后执行。最简单的解决方案是使用Wait函数等待它。
Task.Run(() => ResolveRiver(barges, ref groupNumber)).ContinueWith(t=>
{
IEnumerable<BargeGroup> riverGroups = t.Result;
bargeGroups.AddRange(riverGroups);
}).Wait()
或事件更好,你不需要Task.Run,只需等待延续函数即可:
ResolveRiver(barges, ref groupNumber)).ContinueWith(t=>
{
IEnumerable<BargeGroup> riverGroups = t.Result;
bargeGroups.AddRange(riverGroups);
}).Wait();