StackExchange.Redis:HashSetAsync批量写入无报错却失败,如何判断操作成功?
问题分析与解决方案
一、你的代码存在两个关键问题
- Parallel.For与异步委托不兼容:Parallel.For不支持异步lambda(
async index => {}本质是async void方法),它会在启动异步任务后直接继续执行,不会等待任务完成。大量异步任务还没来得及向Redis发送请求就被终止,这是写入数量远少于10000的核心原因。 - 变量名错误导致异常或重复键:代码中
"id:"+i的i未定义,应该是循环变量index。如果实际代码中存在变量捕获问题(比如误用外部循环变量),会导致多个任务生成相同的键,后写入的值覆盖前一个,最终实际存在的键数量远低于预期。
二、如何判断HashSetAsync调用是否成功
StackExchange.Redis的HashSetAsync提供不同重载,可通过返回值和异常判断执行结果:
- 单个字段重载:
Task<bool> HashSetAsync(RedisKey key, RedisValue hashField, RedisValue value, ...)
返回true表示该字段是新添加的,false表示字段已存在并被更新。如果调用过程中出现网络故障、Redis服务器错误等,会直接抛出RedisException。 - 多个字段重载:
Task<long> HashSetAsync(RedisKey key, HashEntry[] hashFields, ...)
返回值为成功设置的字段数量。同样,执行失败会抛出对应异常。
只要调用未抛出异常,且返回值符合预期,即可确认写入成功。
三、修正后的代码示例
改用Task.WhenAll处理异步并发,确保所有任务执行完成,同时捕获每个任务的执行结果:
var _redis = ConnectionMultiplexer.Connect("localhost"); var _db = _redis.GetDatabase(); // 创建所有异步任务并捕获结果 var tasks = Enumerable.Range(0, 10000) .Select(async index => { var key = $"id:{index}"; try { bool result = await _db.HashSetAsync(key, "Field", "value"); return new { Key = key, Success = true, Detail = result ? "字段新增成功" : "字段更新成功" }; } catch (Exception ex) { return new { Key = key, Success = false, Detail = ex.Message }; } }); // 等待所有任务完成 var results = await Task.WhenAll(tasks); // 统计并输出结果 var successCount = results.Count(r => r.Success); var failCount = results.Count(r => !r.Success); Console.WriteLine($"成功写入:{successCount}条"); Console.WriteLine($"失败写入:{failCount}条"); // 输出失败详情(可选) foreach (var failItem in results.Where(r => !r.Success)) { Console.WriteLine($"键[{failItem.Key}]写入失败:{failItem.Detail}"); }
四、额外注意事项
- 控制并发数:Redis的并发处理能力有限,大量并发请求可能导致服务器压力过大,建议通过
SemaphoreSlim限制同时执行的任务数(比如50-100)。 - 连接复用:
ConnectionMultiplexer应全局单例使用,不要每次请求都创建新连接,否则会导致连接池耗尽。
内容的提问来源于stack exchange,提问作者user194878
相关产品推荐
相关产品推荐

