Skip to content

Commit 939277f

Browse files
committed
选择性使用ConcurrentCache与ConcurrentDictionary
1 parent 3101a78 commit 939277f

File tree

9 files changed

+171
-104
lines changed

9 files changed

+171
-104
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using BenchmarkDotNet.Attributes;
2+
using System;
3+
using System.Collections.Concurrent;
4+
5+
namespace WebApiClientCore.Benchmarks.ConcurrentCacheBenchmark
6+
{
7+
public class Benchmark : IBenchmark
8+
{
9+
private readonly ConcurrentCache<Type, string> cache = new ConcurrentCache<Type, string>();
10+
private readonly ConcurrentDictionary<Type, string> dic = new ConcurrentDictionary<Type, string>();
11+
12+
[Benchmark]
13+
public void ConcurrentCache_GetOrAdd()
14+
{
15+
cache.GetOrAdd(typeof(Benchmark), key => string.Empty);
16+
}
17+
18+
[Benchmark]
19+
public void ConcurrentDictionary_GetOrAdd()
20+
{
21+
dic.GetOrAdd(typeof(Benchmark), key => string.Empty);
22+
}
23+
}
24+
}

WebApiClientCore.Benchmarks/Program.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ class Program
88
{
99
static void Main(string[] args)
1010
{
11-
var benchmarkTypes = typeof(Program).Assembly.GetTypes().Where(item => typeof(IBenchmark).IsAssignableFrom(item));
12-
foreach(var item in benchmarkTypes)
11+
var benchmarkTypes = typeof(Program).Assembly.GetTypes()
12+
.Where(item => typeof(IBenchmark).IsAssignableFrom(item))
13+
.Where(item => item.IsAbstract == false && item.IsClass);
14+
15+
foreach (var item in benchmarkTypes)
1316
{
1417
BenchmarkRunner.Run(item);
15-
}
18+
}
1619
Console.ReadLine();
1720
}
1821
}
Lines changed: 16 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
using BenchmarkDotNet.Attributes;
2-
using Microsoft.Extensions.DependencyInjection;
1+
using Microsoft.Extensions.DependencyInjection;
32
using System;
43
using System.Net.Http;
5-
using System.Text.Json;
64
using System.Threading.Tasks;
5+
using Microsoft.Extensions.DependencyInjection;
76

87
namespace WebApiClientCore.Benchmarks.RequestBenchmark
98
{
10-
/// <summary>
11-
/// 跳过真实的http请求环节的模拟Get请求
12-
/// </summary>
13-
public class Benchmark : IBenchmark
9+
public abstract class BenChmark : IBenchmark
1410
{
15-
private readonly IServiceProvider serviceProvider;
11+
protected IServiceProvider ServiceProvider { get; }
1612

17-
public Benchmark()
18-
{
13+
public BenChmark()
14+
{
1915
var services = new ServiceCollection();
2016

2117
services
@@ -30,97 +26,20 @@ public Benchmark()
3026
.AddHttpApi<IWebApiClientApi>(services, o => o.HttpHost = new Uri("http://webapiclient.com/"))
3127
.AddHttpMessageHandler(() => new MockResponseHandler());
3228

33-
this.serviceProvider = services.BuildServiceProvider();
34-
}
29+
this.ServiceProvider = services.BuildServiceProvider();
3530

36-
/// <summary>
37-
/// 使用WebApiClient.JIT请求
38-
/// </summary>
39-
/// <returns></returns>
40-
[Benchmark]
41-
public async Task<Model> WebApiClient_GetAsync()
42-
{
43-
using var scope = this.serviceProvider.CreateScope();
44-
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientApi>();
45-
return await banchmarkApi.GetAsyc(id: "id");
31+
this.PreheatAsync().Wait();
4632
}
4733

48-
/// <summary>
49-
/// 使用WebApiClientCore请求
50-
/// </summary>
51-
/// <returns></returns>
52-
[Benchmark]
53-
public async Task<Model> WebApiClientCore_GetAsync()
34+
private async Task PreheatAsync()
5435
{
55-
using var scope = this.serviceProvider.CreateScope();
56-
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientCoreApi>();
57-
return await banchmarkApi.GetAsyc(id: "id");
58-
}
59-
60-
/// <summary>
61-
/// 使用原生HttpClient请求
62-
/// </summary>
63-
/// <returns></returns>
64-
[Benchmark]
65-
public async Task<Model> HttpClient_GetAsync()
66-
{
67-
using var scope = this.serviceProvider.CreateScope();
68-
var httpClient = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient(typeof(HttpClient).FullName);
69-
70-
var id = "id";
71-
var request = new HttpRequestMessage(HttpMethod.Get, $"http://webapiclient.com/{id}");
72-
var response = await httpClient.SendAsync(request);
73-
var json = await response.Content.ReadAsByteArrayAsync();
74-
return JsonSerializer.Deserialize<Model>(json);
75-
}
76-
77-
78-
/// <summary>
79-
/// 使用WebApiClient.JIT请求
80-
/// </summary>
81-
/// <returns></returns>
82-
[Benchmark]
83-
public async Task<Model> WebApiClient_PostAsync()
84-
{
85-
using var scope = this.serviceProvider.CreateScope();
86-
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientApi>();
87-
var input = new Model { A = "a" };
88-
return await banchmarkApi.PostAsync(input);
89-
}
90-
91-
/// <summary>
92-
/// 使用WebApiClientCore请求
93-
/// </summary>
94-
/// <returns></returns>
95-
[Benchmark]
96-
public async Task<Model> WebApiClientCore_PostAsync()
97-
{
98-
using var scope = this.serviceProvider.CreateScope();
99-
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientCoreApi>();
100-
var input = new Model { A = "a" };
101-
return await banchmarkApi.PostAsync(input);
102-
}
103-
104-
/// <summary>
105-
/// 使用原生HttpClient请求
106-
/// </summary>
107-
/// <returns></returns>
108-
[Benchmark]
109-
public async Task<Model> HttpClient_PostAsync()
110-
{
111-
using var scope = this.serviceProvider.CreateScope();
112-
var httpClient = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient(typeof(HttpClient).FullName);
113-
114-
var input = new Model { A = "a" };
115-
var json = JsonSerializer.SerializeToUtf8Bytes(input);
116-
var request = new HttpRequestMessage(HttpMethod.Post, $"http://webapiclient.com/")
117-
{
118-
Content = new JsonContent(json)
119-
};
120-
121-
var response = await httpClient.SendAsync(request);
122-
json = await response.Content.ReadAsByteArrayAsync();
123-
return JsonSerializer.Deserialize<Model>(json);
36+
using var scope = this.ServiceProvider.CreateScope();
37+
var api = scope.ServiceProvider.GetService<IWebApiClientApi>();
38+
var coreApi = scope.ServiceProvider.GetService<IWebApiClientCoreApi>();
39+
await api.GetAsyc("id");
40+
await coreApi.GetAsyc("id");
41+
await api.PostAsync(new Model { });
42+
await coreApi.PostAsync(new Model { });
12443
}
12544
}
12645
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using BenchmarkDotNet.Attributes;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using System.Net.Http;
4+
using System.Text.Json;
5+
using System.Threading.Tasks;
6+
7+
namespace WebApiClientCore.Benchmarks.RequestBenchmark
8+
{
9+
/// <summary>
10+
/// 跳过真实的http请求环节的模拟Get请求
11+
/// </summary>
12+
public class GetBenchmark : BenChmark
13+
{
14+
/// <summary>
15+
/// 使用WebApiClient.JIT请求
16+
/// </summary>
17+
/// <returns></returns>
18+
[Benchmark]
19+
public async Task<Model> WebApiClient_GetAsync()
20+
{
21+
using var scope = this.ServiceProvider.CreateScope();
22+
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientApi>();
23+
return await banchmarkApi.GetAsyc(id: "id");
24+
}
25+
26+
/// <summary>
27+
/// 使用WebApiClientCore请求
28+
/// </summary>
29+
/// <returns></returns>
30+
[Benchmark]
31+
public async Task<Model> WebApiClientCore_GetAsync()
32+
{
33+
using var scope = this.ServiceProvider.CreateScope();
34+
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientCoreApi>();
35+
return await banchmarkApi.GetAsyc(id: "id");
36+
}
37+
38+
/// <summary>
39+
/// 使用原生HttpClient请求
40+
/// </summary>
41+
/// <returns></returns>
42+
[Benchmark]
43+
public async Task<Model> HttpClient_GetAsync()
44+
{
45+
using var scope = this.ServiceProvider.CreateScope();
46+
var httpClient = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient(typeof(HttpClient).FullName);
47+
48+
var id = "id";
49+
var request = new HttpRequestMessage(HttpMethod.Get, $"http://webapiclient.com/{id}");
50+
var response = await httpClient.SendAsync(request);
51+
var json = await response.Content.ReadAsByteArrayAsync();
52+
return JsonSerializer.Deserialize<Model>(json);
53+
}
54+
}
55+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using BenchmarkDotNet.Attributes;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using System.Net.Http;
4+
using System.Text.Json;
5+
using System.Threading.Tasks;
6+
7+
namespace WebApiClientCore.Benchmarks.RequestBenchmark
8+
{
9+
/// <summary>
10+
/// 跳过真实的http请求环节的模拟Get请求
11+
/// </summary>
12+
public class PostBenchmark : BenChmark
13+
{
14+
/// <summary>
15+
/// 使用WebApiClient.JIT请求
16+
/// </summary>
17+
/// <returns></returns>
18+
[Benchmark]
19+
public async Task<Model> WebApiClient_PostAsync()
20+
{
21+
using var scope = this.ServiceProvider.CreateScope();
22+
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientApi>();
23+
var input = new Model { A = "a" };
24+
return await banchmarkApi.PostAsync(input);
25+
}
26+
27+
/// <summary>
28+
/// 使用WebApiClientCore请求
29+
/// </summary>
30+
/// <returns></returns>
31+
[Benchmark]
32+
public async Task<Model> WebApiClientCore_PostAsync()
33+
{
34+
using var scope = this.ServiceProvider.CreateScope();
35+
var banchmarkApi = scope.ServiceProvider.GetRequiredService<IWebApiClientCoreApi>();
36+
var input = new Model { A = "a" };
37+
return await banchmarkApi.PostAsync(input);
38+
}
39+
40+
/// <summary>
41+
/// 使用原生HttpClient请求
42+
/// </summary>
43+
/// <returns></returns>
44+
[Benchmark]
45+
public async Task<Model> HttpClient_PostAsync()
46+
{
47+
using var scope = this.ServiceProvider.CreateScope();
48+
var httpClient = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient(typeof(HttpClient).FullName);
49+
50+
var input = new Model { A = "a" };
51+
var json = JsonSerializer.SerializeToUtf8Bytes(input);
52+
var request = new HttpRequestMessage(HttpMethod.Post, $"http://webapiclient.com/")
53+
{
54+
Content = new JsonContent(json)
55+
};
56+
57+
var response = await httpClient.SendAsync(request);
58+
json = await response.Content.ReadAsByteArrayAsync();
59+
return JsonSerializer.Deserialize<Model>(json);
60+
}
61+
}
62+
}

WebApiClientCore/BuildinExtensions/TypeExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Linq;
34
using System.Linq.Expressions;
45
using System.Reflection;
@@ -15,7 +16,7 @@ static class TypeExtensions
1516
/// <summary>
1617
/// 类型的默认值缓存
1718
/// </summary>
18-
private static readonly ConcurrentCache<Type, object?> defaultValueCache = new ConcurrentCache<Type, object?>();
19+
private static readonly ConcurrentDictionary<Type, object?> defaultValueCache = new ConcurrentDictionary<Type, object?>();
1920

2021
/// <summary>
2122
/// 关联的AttributeUsageAttribute是否AllowMultiple

WebApiClientCore/BuildinInterceptor/ActionInterceptor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Diagnostics.CodeAnalysis;
34
using System.Reflection;
45

@@ -12,7 +13,7 @@ class ActionInterceptor : IActionInterceptor
1213
/// <summary>
1314
/// action执行器的缓存
1415
/// </summary>
15-
private static readonly ConcurrentCache<Method, IActionInvoker> invokerCache = new ConcurrentCache<Method, IActionInvoker>();
16+
private static readonly ConcurrentDictionary<Method, IActionInvoker> invokerCache = new ConcurrentDictionary<Method, IActionInvoker>();
1617

1718
/// <summary>
1819
/// 服务上下文

WebApiClientCore/BuildinInterceptor/Invokers/DataValidator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.ComponentModel.DataAnnotations;
34
using System.Linq;
45

@@ -13,7 +14,7 @@ static class DataValidator
1314
/// <summary>
1415
/// 类型的属性否需要验证缓存
1516
/// </summary>
16-
private static readonly ConcurrentCache<Type, bool> cache = new ConcurrentCache<Type, bool>();
17+
private static readonly ConcurrentDictionary<Type, bool> cache = new ConcurrentDictionary<Type, bool>();
1718

1819
/// <summary>
1920
/// 验证参数值输入合法性

WebApiClientCore/Parameters/JsonPatchDocument.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.DependencyInjection;
22
using System;
3+
using System.Collections.Concurrent;
34
using System.Collections.Generic;
45
using System.Diagnostics;
56
using System.Linq.Expressions;
@@ -215,7 +216,7 @@ private class PathVisitor : ExpressionVisitor
215216
/// <summary>
216217
/// 属性名称缓存
217218
/// </summary>
218-
private static readonly ConcurrentCache<MemberInfo, string> staticNameCache = new ConcurrentCache<MemberInfo, string>();
219+
private static readonly ConcurrentDictionary<MemberInfo, string> staticNameCache = new ConcurrentDictionary<MemberInfo, string>();
219220

220221
/// <summary>
221222
/// Path访问器

0 commit comments

Comments
 (0)