我想知道是否可以改进此代码以获得更好的性能。我是服务器端的整个异步的新手,所以请在这里请耐心等待:
con.GetGame(id, game => {
foreach(Player p in game.Team1)
{
p.SomeExtraDetails = GetPlayerDetails(p.Id);
}
// I would like the player data to be set on all players
// before ending up here
});
private PlayerDetails GetPlayerDetails(double playerId)
{
var task = con.GetPlayer(playerId);
PlayerDetails ret = null;
Task continuation = task.ContinueWith(t =>
{
ret = t.Result;
});
continuation.Wait();
return ret;
}
如果我做对了,continuation.Wait();
会阻止主线程。
有没有办法同时运行任务?
答案 0 :(得分:6)
理想情况下,您可以使这些操作一直异步:
private Task<PlayerDetails> GetPlayerDetailsAsync(double playerId)
{
return con.GetPlayer(playerId);
}
con.GetGame(id, game => {
var tasks = game.Team1
.Select(p => new { Player=p, Details=GetPlayerDetailsAsync(p.Id)})
.ToList(); // Force all tasks to start...
foreach(var t in tasks)
{
t.Player.SomeExtraDetails = await t.Details;
}
// all player data is now set on all players
});
如果这不是一个选项(即:您没有使用VS 2012),您可以将代码简化为:
// This is a more efficient version of your existing code
private PlayerDetails GetPlayerDetails(double playerId)
{
var task = con.GetPlayer(playerId);
return task.Result;
}
con.GetGame(id, game => {
// This will run all at once, but block until they're done
Parallel.ForEach(game.Team1, p =>
{
p.SomeExtraDetails = GetPlayerDetails(p.Id);
});
});
答案 1 :(得分:0)
考虑在GetGame页面中使用Parallel.ForEach而不是Task.ContinueWith
答案 2 :(得分:0)
没有LINQ的替代解决方案(虽然我喜欢Reed Copsey的解决方案)。但是,要注意,正如评论中所指出的,此解决方案通过在GetPlayerDetailsAsync()
创建的任务中封装对Task.Run()
的调用来引入开销。
需要.NET 4.5和C#5。
con.GetGame(id, game => {
var tasks = new List<Task>();
foreach(Player p in game.Team1)
{
tasks.Add(Task.Run(async () => p.SomeExtraDetails = await GetPlayerDetailsAsync(p.Id)));
}
Task.WaitAll(tasks.ToArray());
});
private Task<PlayerDetails> GetPlayerDetailsAsync(double playerId)
{
return con.GetPlayerAsync(playerId);
});
此外,为了赶上使用.NET 4.5的基于任务的异步模式(TAP),我强烈建议阅读:Task-based Asynchronous Pattern - 作者:Stephen Toub,Microsoft。