Parallel vs Await vs Result - 哪个更适合延迟执行
Posted
技术标签:
【中文标题】Parallel vs Await vs Result - 哪个更适合延迟执行【英文标题】:Parallel vs Await vs Result - which one is better for deferred execution 【发布时间】:2019-02-05 00:55:41 【问题描述】:实现 #1 - 使用并行循环
var client = new HttpClient();
var processes = new List<Task<object>>();
Parallel.ForEach(urls, url =>
processes.Add(client.GetAsync(url).Result.Content.ReadAsAsync<object>());
);
Task.WhenAll(processes);
实现#2 - 使用异步方法+结果
var client = new HttpClient();
var processes = new List<Task<object>>();
urls.ForEach(url =>
processes.Add(GetChain(client, url));
);
Task.WhenAll(processes);
async Task<object> GetChain(HttpClient client, string url)
return await client.GetAsync(url).Result.Content.ReadAsAsync<object>();
实现 #3 - 使用异步方法 + 等待
var client = new HttpClient();
var processes = new List<Task<object>>();
urls.ForEach(url =>
processes.Add(GetChain(client, url));
);
Task.WhenAll(processes);
async Task<object> GetChain(HttpClient client, string url)
var chain = await client.GetAsync(url);
return await chain.Content.ReadAsAsync<object>();
我喜欢使用 Parallel 循环的实现 #1,但有一个 possibility Parallel 将在每次迭代时创建一个新线程并消耗更多资源。
问题
-
这些方法之间有区别吗,我可以继续使用 Parallel.ForEach 吗?
如果并行循环不好,如何在不创建单独的“异步”方法的情况下改进它?
“await method.Result”是否与“await method1 await method2”相同,#2 vs #3?
附:有两个“等待”调用,因为 HttpClient 请求数据,然后异步读取。
额外的问题 - 这些行是否相同?
method1.Result.method2 // get result immediately
method1.ContinueWith(data => data.Result.method2) // call both methods first
【问题讨论】:
只有在执行一些繁重的并行操作时才使用 Parallel.foreach 有用。将项目添加到列表中并不繁重。混合使用异步和并行是没有用的。 第一个 (Parallel.ForEach()) 只是增加了一个无用的并行级别。填写任务应该是轻量级和快速的。 额外:不一样。但我猜你可能想要一个延续。 示例 2 中的 .Result 杀死了 async/await 的一个分支,甚至可能导致死锁。 另外,List<T>
不是线程安全的,不能像示例 1 中那样使用。
【参考方案1】:
考虑以下示例。它可以帮助您找到问题的答案:
private static readonly List<Uri> Urls = new List<Uri>()
new Uri(""),
new Uri("") ;
....
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var result1 = Urls.Select(GetContent).ToArray();
stopwatch.Stop();
Console.WriteLine($@"Synchronous and NOT In Parallel:stopwatch.ElapsedMilliseconds");
stopwatch.Restart();
var result2 = Urls.AsParallel().Select(GetContent).ToArray();
stopwatch.Stop();
Console.WriteLine($@"Synchronous and In Parallel:stopwatch.ElapsedMilliseconds");
stopwatch.Restart();
var task1 = DoAsyncNotParallel();
task1.Wait();
stopwatch.Stop();
Console.WriteLine($@"Asynchronous and NOT In Parallel:stopwatch.ElapsedMilliseconds");
stopwatch.Restart();
var task2 = DoAsyncInParallel();
task2.Wait();
stopwatch.Stop();
Console.WriteLine($@"Asynchronous and In Parallel:stopwatch.ElapsedMilliseconds");
static async Task<string[]> DoAsyncNotParallel()
List<string> content = new List<string>();
foreach (var uri in Urls)
content.Add(await GetContentAsync(uri));
return content.ToArray();
static async Task<string[]> DoAsyncInParallel()
var tasks = Urls.Select(uri => GetContentAsync(uri));
var content = await Task.WhenAll(tasks);
return content;
private static async Task<string> GetContentAsync(Uri uri)
HttpClient httpClient = new HttpClient();
var response = await httpClient.GetAsync(uri);
var content = await response.Content.ReadAsStringAsync();
return content;
private static string GetContent(Uri uri)
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(uri).Result;
var content = response.Content.ReadAsStringAsync().Result;
return content;
我建议您浏览以下对您有用的链接:
-
Async Programming : Introduction to Async/Await on ASP.NET,作者 斯蒂芬·克利里
How and Where Concurrent Asynchronous I/O with ASP.NET Web API,作者 Tugberk Ugurlu
Parallel Programming with .NET,来自微软
关于问题的最后一部分:
method1.Result.method2();
调用线程被阻塞,直到method1完成,然后method2被调用
method1.ContinueWith(data => data.Result.method2());
调用线程未被阻塞,method1正在异步执行。 一旦 method1 完成,新任务就会像 Task.Run(()=> method1.Result.method2()) 一样运行。在这种情况下,method1.Result 不会阻塞调用线程,因为 method1 已经完成,isCompleted=true
【讨论】:
以上是关于Parallel vs Await vs Result - 哪个更适合延迟执行的主要内容,如果未能解决你的问题,请参考以下文章
callback vs async.js vs promise vs async / await
笑话:await vs setImmediate vs useFakeTimers vs new Promise(setImmediate)
异步 callback vs promise vs async/await
javascript Promise vs Async&Await