C# Redis Pop按项目数列出项目

C# Redis Pop按项目数列出项目,c#,caching,redis,stackexchange.redis,.net-4.5.2,C#,Caching,Redis,Stackexchange.redis,.net 4.5.2,我有一个分布式系统,在一个地方我在redis列表中插入大约10000个项目,然后调用我的多个应用程序钩子来处理项目。我需要的是一些ListLeftPop类型的方法和项目数。它应该从redis列表中删除项目并返回到我的调用应用程序 我正在使用Stackexchange.Resis.extension 我目前的get(而不是pop)方法是 public静态列表GetListItemRange(字符串键、int开始、int chunksize),其中T:class { 列表对象=默认值(列表); 尝试

我有一个分布式系统,在一个地方我在redis列表中插入大约10000个项目,然后调用我的多个应用程序钩子来处理项目。我需要的是一些ListLeftPop类型的方法和项目数。它应该从redis列表中删除项目并返回到我的调用应用程序

我正在使用Stackexchange.Resis.extension

我目前的get(而不是pop)方法是

public静态列表GetListItemRange(字符串键、int开始、int chunksize),其中T:class
{
列表对象=默认值(列表);
尝试
{
if(Muxer!=null&&Muxer.IsConnected&&Muxer.GetDatabase()!=null)
{
var cacheClient=new StackExchangeRedisCacheClient(Muxer,new NewtonsoftSerializer());
var redisValues=cacheClient.Database.ListRange(key,start,(start+chunksize-1));
如果(redisValues.Length>0)
{
obj=Array.ConvertAll(redisValues,value=>JsonConvert.DeserializeObject(value)).ToList();
}
}
}
捕获(例外情况除外)
{
记录器。致命(例如消息,例如);
}
返回obj;
}
我找到了一个片段

 var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer());
                    var redisValues = cacheClient.ListGetFromRight<T>(key);
var cacheClient=new StackExchangeRedisCacheClient(Muxer,new NewtonsoftSerializer());
var redisValues=cacheClient.ListGetFromRight(键);

但是它只适用于单个项目

我假设您正在处理一个队列,您在一个位置插入1000个项目,然后按照插入顺序在多个位置检索它们

你不能用一个命令来实现它,但是你可以用两个命令来实现。您可以编写一个lua脚本来使它们原子化

L范围:

这将列出列表中的前100个元素。这里的偏移量是-100。 请注意,这将以插入时的相反顺序返回项目。因此,需要反转循环以确保队列机制

Ltrim:

这将修剪列表中的前100个元素。这里101是n+1,所以它一定是101。这里的偏移量是101

在lua块中编写它们将确保原子性

让我给你举个简单的例子

在一个位置插入100个图元

你有多个客户 每个人都试图访问这个lua块。假设这里的n值是5。第一 客户端进入并插入前5个元素

将它们保留在lua对象中,然后删除它们

将它们返回到您的代码中,现在您想要的结果是12345,但您得到的是54321。因此,您需要反转循环并执行操作

当下一个客户端进入时,它将获得下一组值

127.0.0.1:6379> lrange list -5 -1
1) "10"
2) "9"
3) "8"
4) "7"
5) "6"
这样你就可以达到你的要求。希望这有帮助

编辑:

Lua脚本:

local result = redis.call('lrange', 'list','-5','-1')
redis.call('ltrim','list','0','-6')
return result
谢谢你,卡提基恩。 我对redis的C#代码如下

 public static RedisResult PopListItemRange(int chunksize, string key)
        {
            RedisResult valreturn = null;
            try
            {

                IDatabase db;
                if (Muxer != null && Muxer.IsConnected && (db = Muxer.GetDatabase()) != null)
                {
                    valreturn = db.ScriptEvaluate(@" local result = redis.call('lrange',KEYS[1],ARGV[1], '-1')
                                                          redis.call('ltrim',KEYS[1],'0',ARGV[2])
                                    return result", new RedisKey[] { key }, flags: CommandFlags.HighPriority, values: new RedisValue[] { -chunksize, -chunksize - 1 });
                }

            }
            catch (Exception ex)
            {
                Logger.Fatal(ex.Message, ex);
            }
            return valreturn;
        }

现在,只要做一个调整,当列表为空时,删除redis键

,这样您就可以一次从列表中弹出所有项目?不是全部,而是通过一些可配置的数字。假设每次有100个用户尝试了var cacheClient=new StackExchangeRedisCacheClient(Muxer,new NewtonsoftSerializer());var redisValues=cacheClient.ListGetFromRight(键);但它只会弹出单个项,是队列还是堆栈?我的意思是lpush lpop(队列)或lpush rpop(堆栈)。谢谢Karthikeyan。我的分析是一样的,我需要两个命令。我可能需要一个lua脚本来实现它。我将尝试制作一个lua脚本,我可以从ScriptEvaluate调用它。但是我一直在寻找一个不需要Lua脚本就可以直接从api获得的解决方案。你能帮我为这些操作创建一个组合Lua脚本吗。在此之前,我只有一个这样的脚本在一个单一的经验
lpush list 1 2 3 .. 100
127.0.0.1:6379> lrange list -5 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> LTRIM list 0 -6
OK
127.0.0.1:6379> lrange list -5 -1
1) "10"
2) "9"
3) "8"
4) "7"
5) "6"
local result = redis.call('lrange', 'list','-5','-1')
redis.call('ltrim','list','0','-6')
return result
 public static RedisResult PopListItemRange(int chunksize, string key)
        {
            RedisResult valreturn = null;
            try
            {

                IDatabase db;
                if (Muxer != null && Muxer.IsConnected && (db = Muxer.GetDatabase()) != null)
                {
                    valreturn = db.ScriptEvaluate(@" local result = redis.call('lrange',KEYS[1],ARGV[1], '-1')
                                                          redis.call('ltrim',KEYS[1],'0',ARGV[2])
                                    return result", new RedisKey[] { key }, flags: CommandFlags.HighPriority, values: new RedisValue[] { -chunksize, -chunksize - 1 });
                }

            }
            catch (Exception ex)
            {
                Logger.Fatal(ex.Message, ex);
            }
            return valreturn;
        }