问题描述
我正在研究Webjob中的列表排序。 当我使用c#List时,它工作正常。但是为了提高性能,我将数据以列表的形式保存到Redis缓存中。
我的最终目标是仅提取最近5分钟的最新数据。
有效的c#代码-
public class MyObject
{
public uint InstrumentID { get; set; }
public decimal Close { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Open { get; set; }
public DateTime TimeStamp { get; set; }
public uint Volume { get; set; }
public DateTime Created { get; } = DateTime.Now;
public DateTime Ttl { get; } = DateTime.Now.AddMinutes(5);
public DateTime? Persisted { get; set; }
public bool IsDead => DateTime.Now > Ttl;
public bool IsPersisted => Persisted.HasValue;
public bool TimetoPersist => IsPersisted == false && DateTime.Now > Created.AddMinutes(5);
public DateTime GetStartOfPeriodByMins(int numMinutes)
{
int oldMinutes = TimeStamp.Minute;
int newMinutes = (oldMinutes / numMinutes) * numMinutes;
DateTime startOfPeriod = new DateTime(TimeStamp.Year,TimeStamp.Month,TimeStamp.Day,TimeStamp.Hour,newMinutes,0);
return startOfPeriod;
}
}
var inputList = new SortedSet<MyObject>(new MyObjectComparer());
inputList.Add(new MyObject() { TimeStamp = DateTime.Now,Open = 9,High = 12,Low = 8,Close = 11,InstrumentID = 2526 });
Thread.Sleep(10000);
inputList.Add(new MyObject() { TimeStamp = DateTime.Now,InstrumentID = 2526 });
Thread.Sleep(50000);
inputList.Add(new MyObject() { TimeStamp = DateTime.Now,InstrumentID = 2526 });
var resultSet = inputList
.GroupBy(i => i.GetStartOfPeriodByMins(5))
.Select(gr =>
new
{
StartOfPeriod = gr.Key,Min = gr.Min(item => item.Open),Max = gr.Max(item => item.Open),Open = gr.OrderBy(item => item.TimeStamp).First().Open,Close = gr.OrderBy(item => item.TimeStamp).Last().Open
});
现在我正在不断将相同的记录插入Redis缓存中。并且虽然尝试获取最后5分钟的数据,但我还是想使用相同的GetStartOfPeriodByMins
概念,但是它需要MyObject类的列表,并且redis返回RedisValue []。
Redis代码-使用StackExchange.Redis程序包
var cache = RedisConnectorHelper.Connection.GetDatabase();
//int i = 0;
for (int i = 0; i < 10000; i++)
{
var tickDataHis = new MyObject()
{
InstrumentID = 2526,Close = 14 + i,High = 16 + i,Low = 11 + i,Open = 12 + i,TimeStamp = DateTime.Now,Volume = 11111
};
// insert into redis
cache.ListRightPush("tickData",JsonConvert.SerializeObject(tickDataHis));
Thread.Sleep(3000);
}
var inputList = cache.ListRange("tickData");
解决方法
我过去使用Redis存储时间序列数据。为了优化数据检索,我使用了一个排序的集合(在这种情况下,有多个集合,但是概念是相同的),其中分数是记录数据的unix时间戳,我使用{ {1}}库。
代码是这样的:
Newtonsoft.Json
通过这种方式,如果您只想检索 最近5分钟的数据,则可以使用var myData = new MyObject() { SomeProperty = "my text" };
long dataTimestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
string serializedData = Newtonsoft.Json.JsonConvert.Convert(myData);
redisDb.SortedSetAdd("mySortedSet",dataTimestamp,serializedData);
方法并通过传递“ now- 5分钟”作为起始分数,这样您就可以只对需要的内容进行反序列化(这当然比对整个列表进行反序列化要便宜):
SortedSetRangeByScore
之后,您可以在linq的帮助下轻松地反序列化数据(考虑到var minutesToTake = 5;
long startingTime = DateTimeOffset.Now.AddMinutes(-minutesToTake).ToUnixTimeMilliseconds();
RedisValue[] redisData = redisDb.SortedSetRangeByScore("mySortedSet",startingTime);
实现了运算符到字符串的转换):
RedisValue
编辑:我没有使用@Hasan EmrahSüngü建议的软件包。也许它更有效,我只是在解释我当时的工作。
编辑2 :MyObject[] myData = redisData.Select(d => JsonConvert.DeserializeObject<MyObject>(d)).ToArray();
是我的redisDb
实例。
编辑3 :有用的参考链接: