【发布时间】: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 中那样使用。
标签: c# multithreading