簡體   English   中英

這是 .NET 中 StackExchange.Redis 中流水線的正確實現嗎?

[英]Is this correct implementation of pipelining in StackExchange.Redis in .NET?

我正在嘗試提高從 Redis 讀取哈希的性能,並且嘗試實現流水線,這是正確的方法嗎?

public Task FetchHashesFromRedis(List<string> redisKeys, CancellationToken cancellationToken) 
{
      var parallel = Environment.ProcessorCount;
      var semafore = new SemaphoreSlim(initialCount: parallel, maxCount: parallel);
      var tasks = new List<Task>();

      for (int i = 0; i < redisKeys.Count; i++)
      {
          var currentKey = redisKeys.ElementAt(i);
          var task = FetchFromRedis(currentKey, semafore, cancellationToken)
          tasks.Add(task);
      }

      return Task.WhenAll(tasks);
}

這段代碼有什么可以改進的?

如果您使用異步 API 和一系列任務,StackExchange.Redis 將自動為您處理所有內容。 您還需要確保在哈希的情況下利用 HSET/HMGET 命令的可變性來減少需要向 Redis 發出的原始命令的數量。

我不確定FetchFromRedis在您提供的代碼的上下文中做了什么。 假設它異步執行 HGET/HMGET/HGETALL 操作之一,並從中返回任務,我懷疑你離得太遠了。 但我還沒有看到你是如何把結果拉出來的?

以下代碼創建並從 Redis 中的 10k 哈希中獲取數據。 這有點微不足道,但展示了您正在尋找的行為。 在我的機器上(當然,我要去本地主機),這在大約 75 毫秒內執行 - 或大約 3.8 微秒/操作。 完成后,結果都在getTasks的任務中可用。

您需要確保(使用實際的數據加載)您不會過度推動它,因為粉碎 StackExchange.Redis 可能會導致它拋出超時異常(基本上如果您排隊太多東西操作可能會卡在多路復用器的消息隊列中並失敗)。

var stopwatch = Stopwatch.StartNew();

var setTasks = new List<Task>();

for (var i = 1; i < 10000; i++)
{
    setTasks.Add(db.HashSetAsync($"hash:{i}", new HashEntry[]{new HashEntry("foo", "bar"), new HashEntry("baz", 3)}));
}

await Task.WhenAll(setTasks);

var getTasks = new List<Task<RedisValue[]>>(); 

for (var i = 1; i < 10000; i++)
{
    getTasks.Add(db.HashGetAsync($"hash:{i}", new RedisValue[]{"foo","baz"}));
}

await Task.WhenAll(getTasks);

stopwatch.Stop();

Console.Write($"total execution time:{stopwatch.ElapsedMilliseconds}");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM