实现#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会在每次迭代时创建一个新线程,并且会消耗更多资源。
问题
P.S。因为HttpClient请求数据,然后异步读取,所以有两个“ await”调用。
其他问题-这些行是否相同?
method1.Result.method2 // get result immediately
method1.ContinueWith(data => data.Result.method2) // call both methods first
答案 0 :(得分: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;
}
我建议您仔细阅读以下对您有用的链接:
关于问题的最后一部分:
method1.Result.method2();
调用线程被阻塞,直到method1完成,然后调用method2
method1.ContinueWith(data => data.Result.method2());
调用线程未被阻塞,method1正在异步执行。 一旦method1完成,新任务就会像Task.Run(()=> {method1.Result.method2()})一样运行。在这种情况下,method1.Result不会阻塞调用线程,因为method1已完成,isCompleted = true