在 .net Core、C# 中并行调用 API 的最佳方法是什么?
What is the best way to cal API calls in parallel in .net Core, C#?
我想并行调用我的 API x 次,以便可以快速完成处理。
我有以下三种方法,我必须并行调用 APIs。我正在尝试了解执行此操作的最佳方式。
基本代码
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
var list = new List<int>();
var listResults = new List<string>();
for (int i = 1; i < 5; i++)
{
list.Add(i);
}
第一种方法使用 Parallel.ForEach
Parallel.ForEach(list,new ParallelOptions() { MaxDegreeOfParallelism = 3 }, index =>
{
var response = client.GetAsync("posts/" + index).Result;
var contents = response.Content.ReadAsStringAsync().Result;
listResults.Add(contents);
Console.WriteLine(contents);
});
Console.WriteLine("After all parallel tasks are done with Parallel for each");
带任务的第二种方法。我不确定这是否并行。如果可以,请告诉我
var loadPosts = new List<Task<string>>();
foreach(var post in list)
{
var response = await client.GetAsync("posts/" + post);
var contents = response.Content.ReadAsStringAsync();
loadPosts.Add(contents);
Console.WriteLine(contents.Result);
}
await Task.WhenAll(loadPosts);
Console.WriteLine("After all parallel tasks are done with Task When All");
使用操作块的第三种方法 - 这是我认为我应该一直做的事情,但我想听听社区的意见
var responses = new List<string>();
var block = new ActionBlock<int>(
async x => {
var response = await client.GetAsync("posts/" + x);
var contents = await response.Content.ReadAsStringAsync();
Console.WriteLine(contents);
responses.Add(contents);
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 6, // Parallelize on all cores
});
for (int i = 1; i < 5; i++)
{
block.Post(i);
}
block.Complete();
await block.Completion;
Console.WriteLine("After all parallel tasks are done with Action block");
接近 2 号。这是一个经验法则:I/O 绑定操作=> 使用 Tasks/WhenAll(异步),计算绑定操作 => 使用并行。 Http 请求是网络 I/O。
foreach (var post in list)
{
async Task<string> func()
{
var response = await client.GetAsync("posts/" + post);
return await response.Content.ReadAsStringAsync();
}
tasks.Add(func());
}
await Task.WhenAll(tasks);
var postResponses = new List<string>();
foreach (var t in tasks) {
var postResponse = await t; //t.Result would be okay too.
postResponses.Add(postResponse);
Console.WriteLine(postResponse);
}
我会使用以下方法,它无法控制并发性(它将并行分派所有 HTTP 请求,与您的第三种方法不同)但它要简单得多 - 它只有一个 await
。
var client = new HttpClient();
var list = new[] { 1, 2, 3, 4, 5 };
var postTasks = list.Select(p => client.GetStringAsync("posts/" + p));
var posts = await Task.WhenAll(postTasks);
foreach (var postContent in posts)
{
Console.WriteLine(postContent);
}
我制作了一个小的控制台应用程序来测试所有方法 ping API "https://jsonplaceholder.typicode.com/todos/{i}" 200 次。
@MikeLimaSierra 方法 1 或 3 是最快的!
Method
DegreeOfParallelism
Time
Not Parallel
n/a
8.4 sec
@LearnAspNet (OP) Method 1
2
5.494 sec
@LearnAspNet (OP) Method 1
30
1.235 sec
@LearnAspNet (OP) Method 3
2
4.750 sec
@LearnAspNet (OP) Method 3
30
1.795 sec
@jamespconnor Method
n/a
21.5 sec
@YuliBonner Method
n/a
21.4 sec
我想并行调用我的 API x 次,以便可以快速完成处理。 我有以下三种方法,我必须并行调用 APIs。我正在尝试了解执行此操作的最佳方式。
基本代码
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
var list = new List<int>();
var listResults = new List<string>();
for (int i = 1; i < 5; i++)
{
list.Add(i);
}
第一种方法使用 Parallel.ForEach
Parallel.ForEach(list,new ParallelOptions() { MaxDegreeOfParallelism = 3 }, index =>
{
var response = client.GetAsync("posts/" + index).Result;
var contents = response.Content.ReadAsStringAsync().Result;
listResults.Add(contents);
Console.WriteLine(contents);
});
Console.WriteLine("After all parallel tasks are done with Parallel for each");
带任务的第二种方法。我不确定这是否并行。如果可以,请告诉我
var loadPosts = new List<Task<string>>();
foreach(var post in list)
{
var response = await client.GetAsync("posts/" + post);
var contents = response.Content.ReadAsStringAsync();
loadPosts.Add(contents);
Console.WriteLine(contents.Result);
}
await Task.WhenAll(loadPosts);
Console.WriteLine("After all parallel tasks are done with Task When All");
使用操作块的第三种方法 - 这是我认为我应该一直做的事情,但我想听听社区的意见
var responses = new List<string>();
var block = new ActionBlock<int>(
async x => {
var response = await client.GetAsync("posts/" + x);
var contents = await response.Content.ReadAsStringAsync();
Console.WriteLine(contents);
responses.Add(contents);
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 6, // Parallelize on all cores
});
for (int i = 1; i < 5; i++)
{
block.Post(i);
}
block.Complete();
await block.Completion;
Console.WriteLine("After all parallel tasks are done with Action block");
接近 2 号。这是一个经验法则:I/O 绑定操作=> 使用 Tasks/WhenAll(异步),计算绑定操作 => 使用并行。 Http 请求是网络 I/O。
foreach (var post in list)
{
async Task<string> func()
{
var response = await client.GetAsync("posts/" + post);
return await response.Content.ReadAsStringAsync();
}
tasks.Add(func());
}
await Task.WhenAll(tasks);
var postResponses = new List<string>();
foreach (var t in tasks) {
var postResponse = await t; //t.Result would be okay too.
postResponses.Add(postResponse);
Console.WriteLine(postResponse);
}
我会使用以下方法,它无法控制并发性(它将并行分派所有 HTTP 请求,与您的第三种方法不同)但它要简单得多 - 它只有一个 await
。
var client = new HttpClient();
var list = new[] { 1, 2, 3, 4, 5 };
var postTasks = list.Select(p => client.GetStringAsync("posts/" + p));
var posts = await Task.WhenAll(postTasks);
foreach (var postContent in posts)
{
Console.WriteLine(postContent);
}
我制作了一个小的控制台应用程序来测试所有方法 ping API "https://jsonplaceholder.typicode.com/todos/{i}" 200 次。 @MikeLimaSierra 方法 1 或 3 是最快的!
Method | DegreeOfParallelism | Time |
---|---|---|
Not Parallel | n/a | 8.4 sec |
@LearnAspNet (OP) Method 1 | 2 | 5.494 sec |
@LearnAspNet (OP) Method 1 | 30 | 1.235 sec |
@LearnAspNet (OP) Method 3 | 2 | 4.750 sec |
@LearnAspNet (OP) Method 3 | 30 | 1.795 sec |
@jamespconnor Method | n/a | 21.5 sec |
@YuliBonner Method | n/a | 21.4 sec |