循环中并行执行异步任务<T>方法



我有一个带有async Task<Result>方法的程序,我需要从循环中并行运行。以下是我尝试的两种方法,第一种(ResolveWidgetsTaskFactoryAsync)按预期工作,但另一种(ResolveWidgetsNotParallelAsync)同步运行,即使每个方法返回为任务。在保持ComputeAsync的异步Task<string>返回类型的同时,我如何编写更好的并行版本?

void Main()
{
var results = ResolveWidgetsTaskFactoryAsync().Result;
results.Dump();
results = ResolveWidgetsNotParallelAsync().Result;
results.Dump();
}
/// <summary>
/// Runs synchronously instead of in parallel
/// /summary>
private async Task<IEnumerable<string>> ResolveWidgetsNotParallelAsync()
{
var values = new[] { "a", "b", "c" };
var widgets = new List<Task<string>>();
foreach (var value in values)
{
Console.WriteLine("Iteration value : " + value);
var widgetTask = ComputeAsync(value);
widgets.Add(widgetTask);
}
return await Task.WhenAll(widgets);
}
/// <summary>
/// Runs as expected, but I'm not sure it's well written
/// /summary>
private async Task<IEnumerable<string>> ResolveWidgetsTaskFactoryAsync()
{
var values = new[] { "a", "b", "c" };
var widgets = new List<Task<string>>();
foreach (var value in values)
{
Console.WriteLine("Iteration value : " + value);
widgets.Add(Task<string>.Factory.StartNew(() => ComputeAsync(value).Result));
}
return await Task.WhenAll(widgets);
}
public async Task<string> ComputeAsync(string value)
{
try
{
Console.WriteLine("Processing value : " + value);
Random rnd = new Random();
var wait = rnd.Next(1000, 5000);
Console.WriteLine("Wait : " + wait);
Thread.Sleep(wait);
return await Task.FromResult(value + " done");
}
catch (Exception e)
{
return null;
}
}

为了以更好的方式编写并行版本,您应该首先认识到您的代码本质上是同步的。其中没有任何异步内容。将同步代码包装在异步API中只会导致复杂性和混乱。因此,我的建议是从代码中剥离所有Task,asyncawait关键字,并使用Parallel类或PLINQ库来并行化它。下面是一个PLINQ示例:

public string Compute(string value)
{
//...
}
private string[] ResolveWidgetsParallel()
{
var values = new[] { "a", "b", "c" };
return values
.AsParallel()
.AsOrdered()
.Select(value => Compute(value))
.ToArray();
}

相关内容

最新更新