From 764cea72bd2b8e1dbe7d39faed00a4750acf554c Mon Sep 17 00:00:00 2001 From: HCricle <15218450198@163.com> Date: Wed, 4 Dec 2024 23:09:38 +0800 Subject: [PATCH] Min the batch --- src/Ao.Cache.Core/CacheHelper.cs | 2 +- src/Ao.Cache.Core/DataFinders.cs | 34 ---- src/Ao.Cache.Core/ICacheVisitor.Batch.cs | 28 +-- .../MemoryCacheVisitor.Batch.cs | 71 ++++--- .../RedisCacheVisitor.Batch.cs | 185 +++++++----------- 5 files changed, 120 insertions(+), 200 deletions(-) delete mode 100644 src/Ao.Cache.Core/DataFinders.cs diff --git a/src/Ao.Cache.Core/CacheHelper.cs b/src/Ao.Cache.Core/CacheHelper.cs index 9f0080d..ed1a543 100644 --- a/src/Ao.Cache.Core/CacheHelper.cs +++ b/src/Ao.Cache.Core/CacheHelper.cs @@ -72,7 +72,7 @@ private Finders BuildFinders(Type instanceType, MethodInfo method) { declareAttr = instanceType.GetCustomAttribute(); } - var proxyAttr = method.GetCustomAttribute(); + var proxyAttr = method.GetCustomAttribute();//TODO: 这里不用反射,而是直接传入 var finder = Factory.Create(); var syncFinder = SyncFactory.CreateSync(); string head = null; diff --git a/src/Ao.Cache.Core/DataFinders.cs b/src/Ao.Cache.Core/DataFinders.cs deleted file mode 100644 index f1a73ce..0000000 --- a/src/Ao.Cache.Core/DataFinders.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Ao.Cache -{ -#if !NETSTANDARD1_0 - - public class DataFinders - { - protected readonly IServiceProvider provider; - - public DataFinders(IServiceProvider provider) - { - { - this.provider = provider; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IDataFinder Get(TimeSpan? cacheTime = null, bool renewal = false) - { - var finder = (IDataFinder)provider.GetService(typeof(IDataFinder)); - if (cacheTime != null) - { - { - finder.Options.WithCacheTime(cacheTime); - finder.Options.WithRenew(renewal); - } - } - return finder; - } - } -#endif -} diff --git a/src/Ao.Cache.Core/ICacheVisitor.Batch.cs b/src/Ao.Cache.Core/ICacheVisitor.Batch.cs index a44e6ed..eb13401 100644 --- a/src/Ao.Cache.Core/ICacheVisitor.Batch.cs +++ b/src/Ao.Cache.Core/ICacheVisitor.Batch.cs @@ -6,32 +6,32 @@ namespace Ao.Cache { public partial interface ICacheVisitor { - IDictionary Exists(IReadOnlyList keys); + long Exists(IReadOnlyList keys); - Task> ExistsAsync(IReadOnlyList keys); + Task ExistsAsync(IReadOnlyList keys); - IDictionary Get(IReadOnlyList keys); + IReadOnlyList Get(IReadOnlyList keys); - Task> GetAsync(IReadOnlyList keys); + Task> GetAsync(IReadOnlyList keys); - IDictionary Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); + long Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); - Task> SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); + Task SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); - IDictionary GetString(IReadOnlyList keys); + IReadOnlyList GetString(IReadOnlyList keys); - Task> GetStringAsync(IReadOnlyList keys); + Task> GetStringAsync(IReadOnlyList keys); - IDictionary SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); + long SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); - Task> SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); + Task SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always); - IDictionary Delete(IReadOnlyList keys); + long Delete(IReadOnlyList keys); - Task> DeleteAsync(IReadOnlyList keys); + Task DeleteAsync(IReadOnlyList keys); - IDictionary Expire(IReadOnlyList keys, TimeSpan? cacheTime); + long Expire(IReadOnlyList keys, TimeSpan? cacheTime); - Task> ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime); + Task ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime); } } diff --git a/src/Ao.Cache.InMemory/MemoryCacheVisitor.Batch.cs b/src/Ao.Cache.InMemory/MemoryCacheVisitor.Batch.cs index 8b21d00..bb311ee 100644 --- a/src/Ao.Cache.InMemory/MemoryCacheVisitor.Batch.cs +++ b/src/Ao.Cache.InMemory/MemoryCacheVisitor.Batch.cs @@ -6,114 +6,109 @@ namespace Ao.Cache.InMemory { public partial class MemoryCacheVisitor { - public IDictionary Delete(IReadOnlyList keys) + public long Delete(IReadOnlyList keys) { - var map = new Dictionary(keys.Count); + var res = 0; for (int i = 0; i < keys.Count; i++) { - var data = keys[i]; - map[data] = Delete(data); + if (Delete(keys[i])) res++; } - return map; + return res; } - public Task> DeleteAsync(IReadOnlyList keys) + public Task DeleteAsync(IReadOnlyList keys) { return Task.FromResult(Delete(keys)); } - public IDictionary Exists(IReadOnlyList keys) + public long Exists(IReadOnlyList keys) { - var map = new Dictionary(keys.Count); + var res = 0; for (int i = 0; i < keys.Count; i++) { - var data = keys[i]; - map[data] = Exists(data); + if (Exists(keys[i])) res++; } - return map; + return res; } - public Task> ExistsAsync(IReadOnlyList keys) + public Task ExistsAsync(IReadOnlyList keys) { return Task.FromResult(Exists(keys)); } - public IDictionary Expire(IReadOnlyList keys, TimeSpan? cacheTime) + public long Expire(IReadOnlyList keys, TimeSpan? cacheTime) { - var map = new Dictionary(keys.Count); + var res = 0; for (int i = 0; i < keys.Count; i++) { - var data = keys[i]; - map[data] = Expire(data, cacheTime); + if (Expire(keys[i],cacheTime)) res++; } - return map; + return res; } - public Task> ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime) + public Task ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime) { return Task.FromResult(Expire(keys, cacheTime)); } - public IDictionary Get(IReadOnlyList keys) + public IReadOnlyList Get(IReadOnlyList keys) { - var map = new Dictionary(keys.Count); + var map = new T[keys.Count]; for (int i = 0; i < keys.Count; i++) { - var data = keys[i]; - map[data] = Get(data); + map[i] = Get(keys[i]); } return map; } - public Task> GetAsync(IReadOnlyList keys) + public Task> GetAsync(IReadOnlyList keys) { return Task.FromResult(Get(keys)); } - public IDictionary GetString(IReadOnlyList keys) + public IReadOnlyList GetString(IReadOnlyList keys) { - var map = new Dictionary(keys.Count); + var map = new string[keys.Count]; for (int i = 0; i < keys.Count; i++) { - var data = keys[i]; - map[data] = GetString(data); + map[i] = GetString(keys[i]); } return map; } - public Task> GetStringAsync(IReadOnlyList keys) + public Task> GetStringAsync(IReadOnlyList keys) { return Task.FromResult(GetString(keys)); } - public IDictionary Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public long Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) { - var map = new Dictionary(datas.Length); + var res = 0; for (int i = 0; i < datas.Length; i++) { var data = datas[i]; - map[data.Key] = Set(data.Key, data.Value, cacheTime, cacheSetIf); + if (Set(data.Key, data.Value, cacheTime, cacheSetIf)) res++; } - return map; + return res; } - public Task> SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public Task SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) { return Task.FromResult(Set(datas, cacheTime, cacheSetIf)); } - public IDictionary SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public long SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) { - var map = new Dictionary(datas.Length); + var res = 0; for (int i = 0; i < datas.Length; i++) { var data = datas[i]; - map[data.Key] = SetString(data.Key, data.Value, cacheTime, cacheSetIf); + if (SetString(data.Key, data.Value, cacheTime, cacheSetIf)) res++; } - return map; + return res; } - public Task> SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public Task SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) { return Task.FromResult(SetString(datas, cacheTime, cacheSetIf)); } diff --git a/src/Ao.Cache.InRedis/RedisCacheVisitor.Batch.cs b/src/Ao.Cache.InRedis/RedisCacheVisitor.Batch.cs index 53b6acb..c6d34b3 100644 --- a/src/Ao.Cache.InRedis/RedisCacheVisitor.Batch.cs +++ b/src/Ao.Cache.InRedis/RedisCacheVisitor.Batch.cs @@ -8,47 +8,13 @@ namespace Ao.Cache.InRedis { public partial class RedisCacheVisitor { - interface IInputCase - { - TOutput Case(in TInput input); - } - class RedisStringInputCase : IInputCase - { - public static readonly RedisStringInputCase Default = new RedisStringInputCase(); - - public string Case(in RedisValue input) - { - return input; - } - } - class NullInputCase : IInputCase - { - public static readonly NullInputCase Default = new NullInputCase(); - - public T Case(in T input) - { - return input; - } - } - readonly struct BatchResult - { - public readonly Task Task; - - public readonly Task[] Results; - - public BatchResult(Task task, Task[] results) - { - Task = task; - Results = results; - } - } - private BatchResult CreateBatch(Func[]> creator) + private async Task BatchRunAsync(Func>> creator) { var batch = Database.CreateBatch(); var tasks = creator(batch); batch.Execute(); - var newTask = Task.WhenAll(tasks); - return new BatchResult(newTask, tasks); + var newTask = await Task.WhenAll(tasks); + return tasks.Count(x => x.IsCompleted && x.Exception == null); } private RedisKey[] AsKeys(IReadOnlyList keys) { @@ -59,125 +25,118 @@ private RedisKey[] AsKeys(IReadOnlyList keys) } return map; } - private IDictionary CreateMap(IReadOnlyList keys, Task[] inputs) - { - return CreateMap(keys, inputs, NullInputCase.Default); - } - private IDictionary CreateMap(IReadOnlyList keys, RedisValue[] values) - { - var type=typeof(T); - var map = new Dictionary(keys.Count); - for (int i = 0; i < values.Length; i++) - { - map[keys[i]] = (T)EntityConvertor.ToEntry(values[i], type); - } - return map; - } - private IDictionary CreateMap(IReadOnlyList keys, - Task[] inputs, IInputCase inputCase) - { - var map = new Dictionary(keys.Count); - for (int i = 0; i < keys.Count; i++) - { - map[keys[i]] = inputCase.Case(inputs[i].Result); - } - return map; - } - public IDictionary Exists(IReadOnlyList keys) + + public long Exists(IReadOnlyList keys) { - return ExistsAsync(keys).GetAwaiter().GetResult(); + var redisKeys = AsKeys(keys); + return Database.KeyExists(redisKeys); } - public async Task> ExistsAsync(IReadOnlyList keys) + public async Task ExistsAsync(IReadOnlyList keys) { - var task = CreateBatch(x => keys.Select(y => x.KeyExistsAsync(y)).ToArray()); - await task.Task; - return CreateMap(keys, task.Results); + var redisKeys = AsKeys(keys); + return await Database.KeyExistsAsync(redisKeys); } - public IDictionary Get(IReadOnlyList keys) + public IReadOnlyList Get(IReadOnlyList keys) { - return GetAsync(keys).GetAwaiter().GetResult(); + var type = typeof(T); + var redisKeys = AsKeys(keys); + var res = Database.StringGet(redisKeys); + return res.Select(x => (T)EntityConvertor.ToEntry(x, type)).ToList(); } - public async Task> GetAsync(IReadOnlyList keys) + public async Task> GetAsync(IReadOnlyList keys) { + var type=typeof(T); var redisKeys = AsKeys(keys); var res = await Database.StringGetAsync(redisKeys); - return CreateMap(keys, res); + return res.Select(x=>(T)EntityConvertor.ToEntry(x,type)).ToList(); } - public IDictionary Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public long Set(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) { - return SetAsync(datas, cacheTime, cacheSetIf).GetAwaiter().GetResult(); + var values = ToStringSet(datas); + var res = Database.StringSet(values, (When)cacheSetIf); + return res ? datas.Length : 0; } - public async Task> SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public async Task SetAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + { + var values = ToStringSet(datas); + var res = await Database.StringSetAsync(values, (When)cacheSetIf); + return res ? datas.Length : 0; + } + + private KeyValuePair[] ToStringSet(KeyValuePair[] datas) { var type = typeof(T); - var task = CreateBatch(x => - datas.Select(y => - x.StringSetAsync(y.Key, EntityConvertor.ToBytes(y.Value,type), cacheTime, (When)cacheSetIf)).ToArray()); - await task.Task; - var map = new Dictionary(datas.Length); - for (int i = 0; i < task.Results.Length; i++) + var values = new KeyValuePair[datas.Length]; + for (int i = 0; i < datas.Length; i++) { - map[datas[i].Key] = task.Results[i].Result; + var item = datas[i]; + values[i] = new KeyValuePair(item.Key, EntityConvertor.ToBytes(item.Value, type)); } - return map; + return values; } - public IDictionary GetString(IReadOnlyList keys) + private KeyValuePair[] ToStringSet(KeyValuePair[] datas) { - return GetStringAsync(keys).GetAwaiter().GetResult(); + var values = new KeyValuePair[datas.Length]; + for (int i = 0; i < datas.Length; i++) + { + var item = datas[i]; + values[i] = new KeyValuePair(item.Key, item.Value); + } + return values; } - public async Task> GetStringAsync(IReadOnlyList keys) + public IReadOnlyList GetString(IReadOnlyList keys) { - var task = CreateBatch(x => keys.Select(y => x.StringGetAsync(y)).ToArray()); - await task.Task; - return CreateMap(keys, task.Results, RedisStringInputCase.Default); + var redisKeys = AsKeys(keys); + var results = Database.StringGet(redisKeys); + return results.Select(x => x.ToString()).ToList(); } - public IDictionary SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + public async Task> GetStringAsync(IReadOnlyList keys) { - return SetStringAsync(datas, cacheTime, cacheSetIf).GetAwaiter().GetResult(); + var redisKeys = AsKeys(keys); + var results=await Database.StringGetAsync(redisKeys); + return results.Select(x => x.ToString()).ToList(); } - public async Task> SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) - { - var task = CreateBatch(x => - datas.Select(y => - x.StringSetAsync(y.Key, y.Value, cacheTime, (When)cacheSetIf)).ToArray()); - await task.Task; - var map = new Dictionary(datas.Length); - for (int i = 0; i < task.Results.Length; i++) - { - map[datas[i].Key] = task.Results[i].Result; - } - return map; + public long SetString(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + { + var values = ToStringSet(datas); + var res = Database.StringSet(values, (When)cacheSetIf); + return res ? datas.Length : 0; + } + + public async Task SetStringAsync(KeyValuePair[] datas, TimeSpan? cacheTime, CacheSetIf cacheSetIf = CacheSetIf.Always) + { + var values = ToStringSet(datas); + var res = await Database.StringSetAsync(values, (When)cacheSetIf); + return res ? datas.Length : 0; } - public IDictionary Delete(IReadOnlyList keys) + public long Delete(IReadOnlyList keys) { - return DeleteAsync(keys).GetAwaiter().GetResult(); + var redisKeys = AsKeys(keys); + return Database.KeyDelete(redisKeys); } - public async Task> DeleteAsync(IReadOnlyList keys) + public async Task DeleteAsync(IReadOnlyList keys) { - var task = CreateBatch(x => keys.Select(y => x.KeyDeleteAsync(y)).ToArray()); - await task.Task; - return CreateMap(keys, task.Results); + var redisKeys = AsKeys(keys); + return await Database.KeyDeleteAsync(redisKeys); } - public IDictionary Expire(IReadOnlyList keys, TimeSpan? cacheTime) + public long Expire(IReadOnlyList keys, TimeSpan? cacheTime) { return ExpireAsync(keys, cacheTime).GetAwaiter().GetResult(); } - public async Task> ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime) + public async Task ExpireAsync(IReadOnlyList keys, TimeSpan? cacheTime) { - var task = CreateBatch(x => keys.Select(y => x.KeyExpireAsync(y, cacheTime)).ToArray()); - await task.Task; - return CreateMap(keys, task.Results); + return await BatchRunAsync(x => keys.Select(y => x.KeyExpireAsync(y, cacheTime))); } } }