Skip to content

Commit

Permalink
[feat]ICache新增单key的Remove,减少数组创建,降低GC压力,提升性能,在Bench压测中提升400倍。
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Sep 14, 2024
1 parent 9e99cc0 commit 2ce84c9
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 46 deletions.
68 changes: 42 additions & 26 deletions NewLife.Core/Caching/Cache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public virtual void Init(String config) { }
[return: MaybeNull]
public abstract T Get<T>(String key);

/// <summary>移除缓存项</summary>
/// <param name="key">键</param>
/// <returns></returns>
public abstract Int32 Remove(String key);

/// <summary>批量移除缓存项</summary>
/// <param name="keys">键集合</param>
/// <returns></returns>
Expand Down Expand Up @@ -358,7 +363,30 @@ public virtual Int64 Bench(Boolean rand = false, Int32 batch = 0)
XTrace.WriteLine($"{Name}性能测试[{(rand ? "随机" : "顺序")}],批大小[{batch}],逻辑处理器 {cpu:n0} 个");

var rs = 0L;
var times = 10_000;
var times = GetTimesPerThread(rand, batch);

// 提前准备Keys,减少性能测试中的干扰
var key = "bstr_";
var key2 = "bint_";
var max = cpu > 64 ? cpu : 64;
var maxTimes = times * max;
if (!rand) maxTimes = max;
_keys = new String[maxTimes];
_keys2 = new String[maxTimes];

var sb = new StringBuilder();
for (var i = 0; i < _keys.Length; i++)
{
sb.Clear();
sb.Append(key);
sb.Append(i);
_keys[i] = sb.ToString();

sb.Clear();
sb.Append(key2);
sb.Append(i);
_keys2[i] = sb.ToString();
}

// 单线程
rs += BenchOne(times, 1, rand, batch);
Expand All @@ -382,6 +410,14 @@ public virtual Int64 Bench(Boolean rand = false, Int32 batch = 0)
return rs;
}

/// <summary>获取每个线程测试次数</summary>
/// <param name="rand"></param>
/// <param name="batch"></param>
/// <returns></returns>
protected virtual Int32 GetTimesPerThread(Boolean rand, Int32 batch) => 10_000;

private String[]? _keys;
private String[]? _keys2;
/// <summary>使用指定线程测试指定次数</summary>
/// <param name="times">次数</param>
/// <param name="threads">线程</param>
Expand All @@ -392,47 +428,27 @@ public virtual Int64 BenchOne(Int64 times, Int32 threads, Boolean rand, Int32 ba
if (threads <= 0) threads = Environment.ProcessorCount;
if (times <= 0) times = threads * 1_000;

//XTrace.WriteLine("");
XTrace.WriteLine($"测试 {times:n0} 项,{threads,3:n0} 线程");

var rs = 3L;

//提前执行一次网络操作,预热链路
var key = "bstr_";
var key = _keys![0];
Set(key, Rand.NextString(32));
_ = Get<String>(key);
Remove(key);

var key2 = "bint_";
var keys = new String[times];
var keys2 = new String[times];
var sb = new StringBuilder();
for (var i = 0; i < times; i++)
{
//keys[i] = key + i;
//keys2[i] = key2 + i;
sb.Clear();
sb.Append(key);
sb.Append(i);
keys[i] = sb.ToString();

sb.Clear();
sb.Append(key2);
sb.Append(i);
keys2[i] = sb.ToString();
}

// 赋值测试
rs += BenchSet(keys, times, threads, rand, batch);
rs += BenchSet(_keys, times, threads, rand, batch);

// 读取测试
rs += BenchGet(keys, times, threads, rand, batch);
rs += BenchGet(_keys, times, threads, rand, batch);

// 删除测试
rs += BenchRemove(keys, times, threads, rand, batch);
rs += BenchRemove(_keys, times, threads, rand, batch);

// 累加测试
rs += BenchInc(keys2, times, threads, rand, batch);
rs += BenchInc(_keys2!, times, threads, rand, batch);

return rs;
}
Expand Down
5 changes: 5 additions & 0 deletions NewLife.Core/Caching/ICache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public interface ICache
[return: MaybeNull]
T Get<T>(String key);

/// <summary>移除缓存项</summary>
/// <param name="key">键</param>
/// <returns></returns>
Int32 Remove(String key);

/// <summary>批量移除缓存项</summary>
/// <param name="keys">键集合</param>
/// <returns></returns>
Expand Down
51 changes: 35 additions & 16 deletions NewLife.Core/Caching/MemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,28 @@ public override T Get<T>(String key)

var rs = item.Visit();
if (rs == null) return default;
if (rs is T t) return t;

return rs.ChangeType<T>();
}

/// <summary>移除缓存项</summary>
/// <param name="key">键</param>
/// <returns>实际移除个数</returns>
public override Int32 Remove(String key)
{
var count = 0;

if (_cache.TryRemove(key, out _))
{
count++;

Interlocked.Decrement(ref _count);
}

return count;
}

/// <summary>批量移除缓存项</summary>
/// <param name="keys">键集合</param>
/// <returns>实际移除个数</returns>
Expand Down Expand Up @@ -522,8 +540,8 @@ public Int64 Inc(Int64 value)
Object oldValue;
do
{
oldValue = _Value ?? 0;
newValue = oldValue.ToLong() + value.ToLong();
oldValue = _Value ?? 0L;
newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) + value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);

Visit();
Expand All @@ -541,8 +559,8 @@ public Double Inc(Double value)
Object oldValue;
do
{
oldValue = _Value ?? 0;
newValue = oldValue.ToDouble() + value.ToDouble();
oldValue = _Value ?? 0d;
newValue = (oldValue is Double n ? n : oldValue.ToDouble()) + value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);

Visit();
Expand All @@ -560,8 +578,8 @@ public Int64 Dec(Int64 value)
Object oldValue;
do
{
oldValue = _Value ?? 0;
newValue = oldValue.ToLong() - value.ToLong();
oldValue = _Value ?? 0L;
newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) - value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);

Visit();
Expand All @@ -579,8 +597,8 @@ public Double Dec(Double value)
Object oldValue;
do
{
oldValue = _Value ?? 0;
newValue = oldValue.ToDouble() - value.ToDouble();
oldValue = _Value ?? 0d;
newValue = (oldValue is Double n ? n : oldValue.ToDouble()) - value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);

Visit();
Expand Down Expand Up @@ -807,19 +825,20 @@ public void Load(Stream stream)
#endregion

#region 性能测试
/// <summary>使用指定线程测试指定次数</summary>
/// <param name="times">次数</param>
/// <param name="threads">线程</param>
/// <param name="rand">随机读写</param>
/// <param name="batch">批量操作</param>
public override Int64 BenchOne(Int64 times, Int32 threads, Boolean rand, Int32 batch)
/// <summary>获取每个线程测试次数</summary>
/// <param name="rand"></param>
/// <param name="batch"></param>
/// <returns></returns>
protected override Int32 GetTimesPerThread(Boolean rand, Int32 batch)
{
var times = base.GetTimesPerThread(rand, batch);

if (rand)
times *= 100;
else
times *= 1000;
times *= 10000;

return base.BenchOne(times, threads, rand, batch);
return times;
}
#endregion
}
Expand Down
11 changes: 7 additions & 4 deletions Test/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private static async Task Main(String[] args)
try
{
#endif
Test1();
Test4();
#if !DEBUG
}
catch (Exception ex)
Expand Down Expand Up @@ -239,9 +239,12 @@ private static void Test4()
if (Console.ReadKey().KeyChar != '1') mode = true;

var batch = 0;
Console.WriteLine();
Console.Write("选择输入批大小[0]:");
batch = Console.ReadLine().ToInt();
if (mode)
{
Console.WriteLine();
Console.Write("选择输入批大小[0]:");
batch = Console.ReadLine().ToInt();
}

Console.Clear();

Expand Down

0 comments on commit 2ce84c9

Please sign in to comment.