Skip to content

Commit

Permalink
优化内存缓存,改进累加性能,最高超过9亿tps
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Sep 15, 2024
1 parent 2ce84c9 commit 6a19f1b
Showing 1 changed file with 96 additions and 66 deletions.
162 changes: 96 additions & 66 deletions NewLife.Core/Caching/MemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public override void Init(String? config)
{
if (_cache.TryGetValue(key, out item) && item != null)
{
if (!item.Expired) return (T?)item.Visit();
if (!item.Expired) return item.Visit<T>();

item.Set(value, expire);

Expand All @@ -107,7 +107,7 @@ public override void Init(String? config)

Interlocked.Increment(ref _count);

return (T?)item.Visit();
return item.Visit<T>();
}
#endregion

Expand Down Expand Up @@ -163,11 +163,7 @@ public override T Get<T>(String key)
{
if (!_cache.TryGetValue(key, out var item) || item == null || item.Expired) return default;

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

return rs.ChangeType<T>();
return item.Visit<T>();
}

/// <summary>移除缓存项</summary>
Expand Down Expand Up @@ -220,7 +216,7 @@ public override Boolean SetExpire(String key, TimeSpan expire)
{
if (!_cache.TryGetValue(key, out var item) || item == null) return false;

item.Set(item.Value, expire);
item.SetExpire(expire);

return true;
}
Expand Down Expand Up @@ -282,7 +278,7 @@ public override T Replace<T>(String key, T value)
{
if (_cache.TryGetValue(key, out item) && item != null)
{
var rs = item.Value;
var rs = item.Visit<T>();
// 如果已经过期,不要返回旧值
if (item.Expired) rs = default(T);

Expand Down Expand Up @@ -315,7 +311,7 @@ public override Boolean TryGetValue<T>(String key, [MaybeNullWhen(false)] out T
if (!_cache.TryGetValue(key, out var item) || item == null) return false;

// 得到已有值
value = item.Visit().ChangeType<T>();
value = item.Visit<T>();

// 是否未过期的有效值
return !item.Expired;
Expand All @@ -335,14 +331,14 @@ public override T GetOrAdd<T>(String key, Func<String, T> callback, Int32 expire
CacheItem? item = null;
do
{
if (_cache.TryGetValue(key, out item) && item != null) return (T?)item.Visit();
if (_cache.TryGetValue(key, out item) && item != null) return item.Visit<T>();

item ??= new CacheItem(callback(key), expire);
} while (!_cache.TryAdd(key, item));

Interlocked.Increment(ref _count);

return (T?)item.Visit();
return item.Visit<T>();
}

/// <summary>累加,原子操作</summary>
Expand Down Expand Up @@ -394,8 +390,8 @@ public override Double Decrement(String key, Double value)
public override IList<T> GetList<T>(String key)
{
var item = GetOrAddItem(key, k => new List<T>());
return item.Visit() as IList<T> ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IList<T>)}");
return item.Visit<IList<T>>() ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IList<T>)}");
}

/// <summary>获取哈希</summary>
Expand All @@ -405,8 +401,8 @@ public override IList<T> GetList<T>(String key)
public override IDictionary<String, T> GetDictionary<T>(String key)
{
var item = GetOrAddItem(key, k => new ConcurrentDictionary<String, T>());
return item.Visit() as IDictionary<String, T> ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IDictionary<String, T>)}");
return item.Visit<IDictionary<String, T>>() ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IDictionary<String, T>)}");
}

/// <summary>获取队列</summary>
Expand All @@ -416,8 +412,8 @@ public override IDictionary<String, T> GetDictionary<T>(String key)
public override IProducerConsumer<T> GetQueue<T>(String key)
{
var item = GetOrAddItem(key, k => new MemoryQueue<T>());
return item.Visit() as IProducerConsumer<T> ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IProducerConsumer<T>)}");
return item.Visit<IProducerConsumer<T>>() ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IProducerConsumer<T>)}");
}

/// <summary>获取栈</summary>
Expand All @@ -427,8 +423,8 @@ public override IProducerConsumer<T> GetQueue<T>(String key)
public override IProducerConsumer<T> GetStack<T>(String key)
{
var item = GetOrAddItem(key, k => new MemoryQueue<T>(new ConcurrentStack<T>()));
return item.Visit() as IProducerConsumer<T> ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IProducerConsumer<T>)}");
return item.Visit<IProducerConsumer<T>>() ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IProducerConsumer<T>)}");
}

/// <summary>获取Set</summary>
Expand All @@ -439,8 +435,8 @@ public override IProducerConsumer<T> GetStack<T>(String key)
public override ICollection<T> GetSet<T>(String key)
{
var item = GetOrAddItem(key, k => new HashSet<T>());
return item.Visit() as ICollection<T> ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(ICollection<T>)}");
return item.Visit<ICollection<T>>() ??
throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(ICollection<T>)}");
}

/// <summary>获取 或 添加 缓存项</summary>
Expand Down Expand Up @@ -476,11 +472,15 @@ protected CacheItem GetOrAddItem(String key, Func<String, Object> valueFactory)
/// <summary>缓存项</summary>
protected class CacheItem
{
private Object? _Value;
/// <summary>数值类型</summary>
public TypeCode TypeCode { get; set; }

private Int64 _valueLong;
private Object? _value;
/// <summary>数值</summary>
public Object? Value { get => _Value; set => _Value = value; }
public Object? Value { get => IsInt() ? _valueLong : _value; }

/// <summary>过期时间</summary>
/// <summary>过期时间。系统启动以来的毫秒数</summary>
public Int64 ExpiredTime { get; set; }

/// <summary>是否过期</summary>
Expand All @@ -497,54 +497,82 @@ protected class CacheItem
/// <summary>设置数值和过期时间</summary>
/// <param name="value"></param>
/// <param name="expire">过期时间,秒</param>
public void Set(Object? value, Int32 expire)
{
Value = value;

var now = VisitTime = Runtime.TickCount64;
if (expire <= 0)
ExpiredTime = Int64.MaxValue;
else
ExpiredTime = now + expire * 1000L;
}
public void Set<T>(T value, Int32 expire) => Set(value, TimeSpan.FromSeconds(expire));

/// <summary>设置数值和过期时间</summary>
/// <param name="value"></param>
/// <param name="expire">过期时间,秒</param>
public void Set(Object? value, TimeSpan expire)
public void Set<T>(T value, TimeSpan expire)
{
Value = value;
var type = typeof(T);
TypeCode = type.GetTypeCode();

if (IsInt())
_valueLong = value.ToLong();
else
_value = value;

SetExpire(expire);
}

/// <summary>设置过期时间</summary>
/// <param name="expire"></param>
public void SetExpire(TimeSpan expire)
{
var now = VisitTime = Runtime.TickCount64;
if (expire == TimeSpan.Zero)
ExpiredTime = Int64.MaxValue;
else
ExpiredTime = now + (Int64)expire.TotalMilliseconds;
}

private Boolean IsInt() => TypeCode >= TypeCode.SByte && TypeCode <= TypeCode.UInt64;
//private Boolean IsDouble() => TypeCode is TypeCode.Single or TypeCode.Double or TypeCode.Decimal;

/// <summary>更新访问时间并返回数值</summary>
/// <returns></returns>
public Object? Visit()
public T? Visit<T>()
{
VisitTime = Runtime.TickCount64;
return Value;

if (IsInt())
{
// 存入取出相同,大多数时候走这里
if (_valueLong is T n) return n;

return _valueLong.ChangeType<T>();
}
else
{
var rs = _value;
if (rs == null) return default;

// 存入取出相同,大多数时候走这里
if (rs is T t) return t;

// 复杂类型返回空值,避免ChangeType失败抛出异常
if (typeof(T).GetTypeCode() == TypeCode.Object) return default;

return rs.ChangeType<T>();
}
}

/// <summary>递增</summary>
/// <param name="value"></param>
/// <returns></returns>
public Int64 Inc(Int64 value)
{
// 原子操作
Int64 newValue;
Object oldValue;
do
// 如果不是整数,先转为整数
if (!IsInt())
{
oldValue = _Value ?? 0L;
newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) + value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);
_valueLong = _value.ToLong();
TypeCode = TypeCode.Int64;
}

Visit();
// 原子操作
var newValue = Interlocked.Add(ref _valueLong, value);

VisitTime = Runtime.TickCount64;

return newValue;
}
Expand All @@ -556,14 +584,14 @@ public Double Inc(Double value)
{
// 原子操作
Double newValue;
Object oldValue;
Object? oldValue;
do
{
oldValue = _Value ?? 0d;
oldValue = _value;
newValue = (oldValue is Double n ? n : oldValue.ToDouble()) + value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);
} while (Interlocked.CompareExchange(ref _value, newValue, oldValue) != oldValue);

Visit();
VisitTime = Runtime.TickCount64;

return newValue;
}
Expand All @@ -573,16 +601,17 @@ public Double Inc(Double value)
/// <returns></returns>
public Int64 Dec(Int64 value)
{
// 原子操作
Int64 newValue;
Object oldValue;
do
// 如果不是整数,先转为整数
if (!IsInt())
{
oldValue = _Value ?? 0L;
newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) - value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);
_valueLong = _value.ToLong();
TypeCode = TypeCode.Int64;
}

Visit();
// 原子操作
var newValue = Interlocked.Add(ref _valueLong, -value);

VisitTime = Runtime.TickCount64;

return newValue;
}
Expand All @@ -594,14 +623,14 @@ public Double Dec(Double value)
{
// 原子操作
Double newValue;
Object oldValue;
Object? oldValue;
do
{
oldValue = _Value ?? 0d;
oldValue = _value;
newValue = (oldValue is Double n ? n : oldValue.ToDouble()) - value;
} while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue);
} while (Interlocked.CompareExchange(ref _value, newValue, oldValue) != oldValue);

Visit();
VisitTime = Runtime.TickCount64;

return newValue;
}
Expand Down Expand Up @@ -731,7 +760,8 @@ public void Save(Stream stream)
bn.Write(item.Key);
bn.Write((Int32)(ci.ExpiredTime / 1000));

var type = ci.Value?.GetType();
var value = ci.Value;
var type = value?.GetType();
if (type == null)
{
bn.Write((Byte)TypeCode.Empty);
Expand All @@ -742,11 +772,11 @@ public void Save(Stream stream)
bn.Write((Byte)code);

if (code != TypeCode.Object)
bn.Write(ci.Value);
bn.Write(value);
else
{
bn.Write(type.FullName);
if (ci.Value != null) bn.Write(Binary.FastWrite(ci.Value));
if (value != null) bn.Write(Binary.FastWrite(value));
}
}
}
Expand Down

0 comments on commit 6a19f1b

Please sign in to comment.