/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/DistributedCacheBenchmarks.cs
234 строки
8 KB
Marc Gravell
HybridCache: relocate to dotnet/extensions (#57670)
12 сен 2024, 17:31
Не верифицирован
12 сен 2024, 17:31
6c0bf68
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Linq; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; namespace Microsoft.Extensions.Caching.Benchmarks; [MemoryDiagnoser, ShortRunJob] public class DistributedCacheBenchmarks : IDisposable { private readonly IBufferDistributedCache sqlServer, redis; private readonly ConnectionMultiplexer multiplexer; private readonly Random random = new Random(); private readonly string[] keys; private readonly Task<byte[]?>[] pendingBlobs = new Task<byte[]?>[OperationsPerInvoke]; // create a local DB named CacheBench, then // dotnet tool install --global dotnet-sql-cache // dotnet sql-cache create "Data Source=.;Initial Catalog=CacheBench;Integrated Security=True;Trust Server Certificate=True" dbo BenchmarkCache private const string SqlServerConnectionString = "Data Source=.;Initial Catalog=CacheBench;Integrated Security=True;Trust Server Certificate=True"; private const string RedisConfigurationString = "127.0.0.1,AllowAdmin=true"; public const int OperationsPerInvoke = 256; public void Dispose() { (sqlServer as IDisposable)?.Dispose(); (redis as IDisposable)?.Dispose(); multiplexer.Dispose(); } public enum BackendType { Redis, SqlServer, } [Params(BackendType.Redis, BackendType.SqlServer)] public BackendType Backend { get; set; } = BackendType.Redis; private IBufferDistributedCache _backend = null!; public DistributedCacheBenchmarks() { var services = new ServiceCollection(); services.AddDistributedSqlServerCache(options => { options.TableName = "BenchmarkCache"; options.SchemaName = "dbo"; options.ConnectionString = SqlServerConnectionString; }); sqlServer = (IBufferDistributedCache)services.BuildServiceProvider().GetRequiredService<IDistributedCache>(); multiplexer = ConnectionMultiplexer.Connect(RedisConfigurationString); services = new ServiceCollection(); services.AddStackExchangeRedisCache(options => { options.ConnectionMultiplexerFactory = () => Task.FromResult<IConnectionMultiplexer>(multiplexer); }); redis = (IBufferDistributedCache)services.BuildServiceProvider().GetRequiredService<IDistributedCache>(); keys = new string[10000]; for (int i = 0; i < keys.Length; i++) { keys[i] = Guid.NewGuid().ToString(); } } [GlobalSetup] public void GlobalSetup() { // reset _backend = Backend switch { BackendType.Redis => redis, BackendType.SqlServer => sqlServer, _ => throw new ArgumentOutOfRangeException(nameof(Backend)), }; _backend.Get(new Guid().ToString()); // just to touch it first switch (Backend) { case BackendType.SqlServer: using (var conn = new SqlConnection(SqlServerConnectionString)) { using var cmd = conn.CreateCommand(); cmd.CommandText = "truncate table dbo.BenchmarkCache"; conn.Open(); cmd.ExecuteNonQuery(); } break; case BackendType.Redis: using (var multiplexer = ConnectionMultiplexer.Connect(RedisConfigurationString)) { multiplexer.GetServer(multiplexer.GetEndPoints().Single()).FlushDatabase(); } break; } var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) }; options.SlidingExpiration = Sliding ? TimeSpan.FromMinutes(5) : null; var value = new byte[PayloadSize]; foreach (var key in keys) { random.NextBytes(value); _backend.Set(key, value, options); } } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public int GetSingleRandom() { int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += _backend.Get(RandomKey())?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public int GetConcurrentRandom() { Func<Task<byte[]?>> callback = () => _backend.GetAsync(RandomKey()); for (int i = 0; i < OperationsPerInvoke; i++) { pendingBlobs[i] = Task.Run(callback); } int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (pendingBlobs[i].Result)?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public async Task<int> GetSingleRandomAsync() { int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (await _backend.GetAsync(RandomKey()))?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public async Task<int> GetConcurrentRandomAsync() { Func<Task<byte[]?>> callback = () => _backend.GetAsync(RandomKey()); for (int i = 0; i < OperationsPerInvoke; i++) { pendingBlobs[i] = Task.Run(callback); } int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (await pendingBlobs[i])?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public int GetSingleFixed() { int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += _backend.Get(FixedKey())?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public int GetConcurrentFixed() { Func<Task<byte[]?>> callback = () => _backend.GetAsync(FixedKey()); for (int i = 0; i < OperationsPerInvoke; i++) { pendingBlobs[i] = Task.Run(callback); } int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (pendingBlobs[i].Result)?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public async Task<int> GetSingleFixedAsync() { int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (await _backend.GetAsync(FixedKey()))?.Length ?? 0; } return total; } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public async Task<int> GetConcurrentFixedAsync() { Func<Task<byte[]?>> callback = () => _backend.GetAsync(FixedKey()); for (int i = 0; i < OperationsPerInvoke; i++) { pendingBlobs[i] = Task.Run(callback); } int total = 0; for (int i = 0; i < OperationsPerInvoke; i++) { total += (await pendingBlobs[i])?.Length ?? 0; } return total; } private string FixedKey() => keys[42]; private string RandomKey() => keys[random.Next(keys.Length)]; [Params(1024, 128, 10 * 1024)] public int PayloadSize { get; set; } = 1024; [Params(true, false)] public bool Sliding { get; set; } = true; }