using BenchmarkDotNet.Attributes;
namespace tutorials.ApiParallelTest;
public class ApiParallelTest{
private static readonly HttpClient HttpClient = new();
private const int TaskCount = 1000;
[Benchmark]
public async Task<List<int>> ForEachApi(){
List<int> list = new();
var fakeTasks = Enumerable.Range(0, TaskCount)
.Select(_ => new Func<Task<int>>(() => SomeAsyncRequest(HttpClient))).ToList();
foreach(var task in fakeTasks){
list.Add(await task());
}
return list;
}
[Benchmark]
public async Task<List<int>> UnlimitedParallelForeachApi(){
List<int> list = new();
var fakeTasks = Enumerable.Range(0, TaskCount)
.Select(_ =>
new Func<int>(() => SomeAsyncRequest(HttpClient).GetAwaiter().GetResult())).ToList();
Parallel.For(0, TaskCount, i => list.Add(fakeTasks[i]()));
return list;
}
[Benchmark]
public async Task<List<int>> MaxParallelForeachApi(int maxDegreeParallelism){
List<int> list = new();
var fakeTasks = Enumerable.Range(0, TaskCount)
.Select(_ =>
new Func<int>(() => SomeAsyncRequest(HttpClient).GetAwaiter().GetResult())).ToList();
Parallel.For(0, TaskCount, new ParallelOptions{
MaxDegreeOfParallelism = maxDegreeParallelism,
}, i => list.Add(fakeTasks[i]()));
return list;
}
[Benchmark]
public async Task<List<int>> WhenAllApi(){
var fakeTasks = Enumerable.Range(0, TaskCount)
.Select(_ => SomeAsyncRequest(HttpClient));
var result = await Task.WhenAll(fakeTasks);
return result.ToList();
}
[Benchmark]
public async Task<List<int>> CustomAsyncParallelv1() => await ParallelAndAsyncApi(1);
[Benchmark]
public async Task<List<int>> CustomAsyncParallelv2() => await ParallelAndAsyncApi(10);
[Benchmark]
public async Task<List<int>> CustomAsyncParallelv3() => await ParallelAndAsyncApi(100);
public async Task<List<int>> ParallelAndAsyncApi(int batches){
List<int> list = new();
var fakeTasks = Enumerable.Range(0, TaskCount)
.Select(_ => new Func<Task<int>>(() => SomeAsyncRequest(HttpClient))).ToList();
await CustomParallelAndAsyncForeach(fakeTasks, batches, async func =>{
list.Add(await func());
});
return list;
}
public static Task CustomParallelAndAsyncForeach<T>(
IEnumerable<T> source,
int degreeOfParallelization,
Func<T, Task> body)
{
async Task AwaitPartition(IEnumerator<T> partition)
{
using(partition){
while(partition.MoveNext()){
await body(partition.Current);
}
}
}
return Task.WhenAll(
System.Collections.Concurrent.Partitioner
.Create(source)
.GetPartitions(degreeOfParallelization)
.AsParallel()
.Select(AwaitPartition)
);
}
private static async Task<int> SomeAsyncRequest(HttpClient httpClient){
var response = await httpClient.GetStringAsync($"");
var user = JsonSerializer.Deserialize<SomeUserData>(response);
return user!.Data;
}
}