gpt4 book ai didi

c# - 如果结果是 MultiBulk,如何从 RedisResult 检索值

转载 作者:行者123 更新时间:2023-12-01 23:30:49 37 4
gpt4 key购买 nike

我可以通过执行如下命令来检索 Redis 数据库中的所有键:

RedisResult allRedisKeys = redisDatabase.Execute("KEYS", new List<object>
{
"*"
})

但是我无法使用变量 allRedisKeys,因为它的 _value 字段是私有(private)的。如何从 RedisResult 中提取值?就我而言,_value 持有 RedisResult[],allRedisKeys 拥有 RedisType.MultiBulk 的 RedisType。

最佳答案

首先,根据 the documentation ,不要在生产环境中使用KEYS命令。但是,您可以使用 .Keys每个服务器的方法,但这需要单独查询每个服务器(并且它的 O(N) 所以也不是最好的)。

要获得更快(但更复杂)的解决方案,请查看 this answer作者:马克·格拉维尔。基本上,您将所有 key 存储在一个 SET 中,这样您就有 O(1) 的响应时间。

这是我对他建议的实现:

/// <summary>
/// Class that keeps track of cache keys and the expiration of said keys.
/// Uses a LIST to store the keys because it's faster than using SCAN on the entire Redis database.
/// Expirations are stored as ticks.
/// </summary>
public static class KeyAndExpirationTracker
{
private const string ALL_KEYS = "ALL_KEYS";
private const string EXPIRATION_SUFFIX = "|EXPIRATION";

public static void StoreKeyAndExpiration(IDatabase db, string key, TimeSpan? timeToLive, ITransaction transaction)
{
string expiryKey = $"{key}{EXPIRATION_SUFFIX}";
// although Redis will automatically replace an existing key,
// we still have to remove this in case this we went from having an expiration to not expiring
db.KeyDelete(expiryKey);

// add the item key to the list of keys
transaction.SetAddAsync(key);
// add the separate cache item for expiration (if necessary)
if (timeToLive.HasValue)
{
DateTime expiry;
try
{
expiry = DateTime.UtcNow.Add(timeToLive.Value);
transaction.StringSetAsync(expiryKey, expiry.Ticks.ToString());
}
catch (ArgumentOutOfRangeException)
{
// no expiration then
}
}
}

public static void StoreKeyAndExpiration(IDatabase db, string key, DateTime? expiration, ITransaction transaction)
{
string expiryKey = $"{key}{EXPIRATION_SUFFIX}";
// although Redis will automatically replace an existing key, we still have to remove this in case this we went from having an expiration to not expiring
db.KeyDelete(expiryKey);

// add the item key to the list of keys for this client type
transaction.SetAddAsync(cacheKey, key);
// add the separate cache item for expiration (if necessary)
if (expiration.HasValue)
{
transaction.StringSetAsync(expiryKey, expiration.Value.Ticks.ToString());
}
}

public static IEnumerable<string> GetKeys(IDatabase db)
{
RedisValue[] keys = db.SetMembers(ALL_KEYS));
if (keys.Length == 0)
return new string[0];

List<string> expiredKeys = new List<string>(keys.Count());
List<string> ret = new List<string>(keys.Count());

// get expiration values using SORT with GET: https://redis.io/commands/sort
RedisValue[] results = db.Sort(
ALL_KEYS,
sortType: SortType.Alphabetic,
by: "notarealkey", // a (hopefully) non-existent key which causes the list to actually not be sorted
get: new RedisValue[] { $"*{EXPIRATION_SUFFIX}", "#" } // # = "get the list item itself" which means the key in our case
));

// SORT results will be in the same order as the GET parameters:
// result[0] = expiration (= null if no matching expiration item found)
// result[1] = key
// (repeat)
for (int i = 0; i < results.Length; i += 2)
{
string key = results[i + 1].Replace(EXPIRATION_SUFFIX, string.Empty);

RedisValue expiryRedis = results[i];
long ticks;
if (long.TryParse(expiryRedis, out ticks))
{
DateTime expiry = new DateTime(ticks, DateTimeKind.Utc);
if (expiry <= DateTime.UtcNow)
expiredKeys.Add(key); // expired: add to list for removal
else
ret.Add(key);
}
else
ret.Add(key);
}

// remove any expired keys from list
if (expiredKeys.Count > 0)
{
IBatch batch = db.CreateBatch();
batch.SetRemoveAsync(cacheKey, expiredKeys.ConvertAll(x => (RedisValue)x).ToArray());
foreach (string expiredKey in expiredKeys)
{
batch.KeyDeleteAsync(expiredKey);
}
batch.Execute();
}

return ret;
}

public static void RemoveKeyAndExpiration(IDatabase db, string key, ITransaction transaction)
{
// remove the key from the list and its corresponding expiration value
string expiryKey = $"{key}{EXPIRATION_SUFFIX}";
transaction.SetRemoveAsync(ALL_KEYS, key);
transaction.KeyDeleteAsync(expiryKey);
}

}

注意:StoreKeyAndExpirationRemoveKeyAndExpiration 方法都采用 ITransaction,因为我在执行这些操作时会同时添加或删除项目缓存,所以我想将它们全部包装到一个事务中。如果调用方法想要向其中添加更多操作,则事务不会在此处执行。

关于c# - 如果结果是 MultiBulk,如何从 RedisResult 检索值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58864724/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com