.Net Faster介绍
Github地址:https://github.com/microsoft/FASTER
官网网址:https://microsoft.github.io/FASTER/
官方文档地址:https://microsoft.github.io/FASTER/docs/quick-start-guide/
1.介绍
Faster 项目提供了两个工件
- Faster KV [一个并发键值存储 + 缓存(在 C# 和 C++ 中提供),C# 中的 FasterKV 键值存储和缓存适用于 .NET Framework 和 .NET core,并且可以在单线程和高并发设置中使用。Faster KV 可用作传统并发数据结构(例如 .NET ConcurrentDictionary)的高性能替代品,并且还支持大于内存的数据。]
- Faster Log[C# 中的高性能并发持久可恢复日志、迭代器和随机读取器库。它支持非常频繁的低延迟提交操作,并且可以快速使磁盘带宽饱和。]
本文介绍的是Faster KV
Java中也有类似的高性能的内存缓存-Caffeine
2.测试
1.新建项目[略]
2.安装依赖
dotnet add package Microsoft.FASTER.Core --version 2.5.14
3.使用
// See https://aka.ms/new-console-template for more information
using FASTER.core;
InMemorySample();
DiskSample();
Console.WriteLine("Press <ENTER> to end");
Console.ReadLine();
static void InMemorySample()
{
Console.WriteLine("In-Memory Sample:\n");
// 数据存储在“d:/coreqi”中
//using var settings = new FasterKVSettings<long, string>("d:/coreqi");
// 若传递控制,则缓存数据则纯粹的保存在内存中
using var settings = new FasterKVSettings<long, long>(null);
using var store = new FasterKV<long, long>(settings);
// 创建一个回调函数
// 可以通过扩展this或FunctionsBase来编写自己的。
var funcs = new SimpleFunctions<long, long>((a, b) => a + b);
// 对faster的每个逻辑调用序列都与一个faster会话相关联。
// 单个会话内不允许并发
using var session = store.NewSession(funcs);
long key = 1, value = 1, output = 0;
// 将值盲目更新到存储中(不检查先前的值)
session.Upsert(ref key, ref value);
// 从内存读取并同步返回
var status = session.Read(ref key, ref output);
if (status.Found && output == value)
{
Console.WriteLine("(1) Success!");
}
else
{
Console.WriteLine("(1) Error!");
}
/// 删除
session.Delete(ref key);
status = session.Read(ref key, ref output);
if (status.Found)
{
Console.WriteLine("(2) Error!");
}
else
{
Console.WriteLine("(2) Success!");
}
// 执行两次读取-修改-写入(求和),验证结果
key = 2;
long input1 = 25, input2 = 27;
session.RMW(ref key, ref input1);
session.RMW(ref key, ref input2);
status = session.Read(ref key, ref output);
if (status.Found && output == input1 + input2)
{
Console.WriteLine("(3) Success!");
}
else
{
Console.WriteLine("(3) Error!");
}
// 使用RMW和自定义函数执行TryAdd
using var tryAddSession = store.NewSession(new TryAddFunctions<long, long>());
key = 3; input1 = 30; input2 = 31;
// 首次尝试添加-成功;状态应为NotFound(不存在)
status = tryAddSession.RMW(ref key, ref input1);
// 第二次TryAdd-失败;状态应为“已找到”(已存在)
var status2 = tryAddSession.RMW(ref key, ref input2);
// 读取,结果应为input1(第一个TryAdd)
var status3 = session.Read(ref key, ref output);
if (status.NotFound && status2.Found && status3.Found && output == input1)
{
Console.WriteLine("(4) Success!");
}
else
{
Console.WriteLine("(4) Error!");
}
}
static void DiskSample()
{
Console.WriteLine("\nDisk Sample:\n");
long key = 1, value = 1, output = 0;
// 根据指定的基本目录路径创建FasterKV配置。
using var config = new FasterKVSettings<long, long>("./database") { TryRecoverLatest = true };
Console.WriteLine($"FasterKV config:\n{config}\n");
// 使用指定的配置创建存储
using var store = new FasterKV<long, long>(config);
var funcs = new SimpleFunctions<long, long>((a, b) => a + b);
using var session = store.NewSession(funcs);
if (store.RecoveredVersion == 1) // 没有恢复
{
Console.WriteLine("Clean start; upserting key-value pair");
// // 将值盲目更新到存储中(不检查先前的值)
session.Upsert(ref key, ref value);
// 获取检查点,以便持久化数据以进行恢复
Console.WriteLine("Taking full checkpoint");
store.TryInitiateFullCheckpoint(out _, CheckpointType.Snapshot);
store.CompleteCheckpointAsync().AsTask().GetAwaiter().GetResult();
}
else
{
Console.WriteLine($"Recovered store to version {store.RecoveredVersion}");
}
// 读取从内存返回并同步返回
var status = session.Read(ref key, ref output);
if (status.Found && output == value)
{
Console.WriteLine("(1) Success!");
}
else
{
Console.WriteLine("(1) Error!");
}
// 强制将记录刷新到磁盘并从内存中逐出,以便从磁盘进行下一次读取
store.Log.FlushAndEvict(true);
// 从磁盘读取将返回PENDING状态,结果可通过异步IFunctions回调获得
// 或通过在此线程上CompletePendingWithOutputs,如下所示
status = session.Read(ref key, ref output);
if (status.IsPending)
{
session.CompletePendingWithOutputs(out var iter, true);
while (iter.Next())
{
if (iter.Current.Status.Found && iter.Current.Output == value)
{
Console.WriteLine("(2) Success!");
}
else
{
Console.WriteLine("(2) Error!");
}
}
iter.Dispose();
}
else
{
Console.WriteLine("(2) Error!");
}
/// 删除密key,读取以验证删除
session.Delete(ref key);
status = session.Read(ref key, ref output);
if (status.Found)
{
Console.WriteLine("(3) Error!");
}
else
{
Console.WriteLine("(3) Success!");
}
// 执行两次读取-修改-写入(求和),验证结果
key = 2;
long input1 = 25, input2 = 27;
session.RMW(ref key, ref input1);
session.RMW(ref key, ref input2);
status = session.Read(ref key, ref output);
if (status.Found && output == input1 + input2)
{
Console.WriteLine("(4) Success!");
}
else
{
Console.WriteLine("(4) Error!");
}
// 使用RMW和自定义函数执行TryAdd
using var tryAddSession = store.NewSession(new TryAddFunctions<long, long>());
key = 3; input1 = 30; input2 = 31;
// 首次尝试添加-成功;状态应为NOTFOUND(不存在)
status = tryAddSession.RMW(ref key, ref input1);
// 第二次TryAdd-失败;状态应为OK(已存在)
var status2 = tryAddSession.RMW(ref key, ref input2);
// 读取,结果应为input1(第一个TryAdd)
var status3 = session.Read(ref key, ref output);
if (!status.Found && status2.Found && status3.Found && output == input1)
{
Console.WriteLine("(5) Success!");
}
else
{
Console.WriteLine("(5) Error!");
}
}