当前位置: 首页 > 面试题库 >

Stackexchange.Redis中的流水线与批处理

赵雪峰
2023-03-14
问题内容

我试图在尽可能短的时间内插入大量(-ish)元素,并且尝试了以下两种选择:

1)流水线:

List<Task> addTasks = new List<Task>();
for (int i = 0; i < table.Rows.Count; i++)
{
    DataRow row = table.Rows[i];
    Task<bool> addAsync = redisDB.SetAddAsync(string.Format(keyFormat, row.Field<int>("Id")), row.Field<int>("Value"));
    addTasks.Add(addAsync);
}
Task[] tasks = addTasks.ToArray();
Task.WaitAll(tasks);

2)批处理:

List<Task> addTasks = new List<Task>();
IBatch batch = redisDB.CreateBatch();
for (int i = 0; i < table.Rows.Count; i++)
{
    DataRow row = table.Rows[i];
    Task<bool> addAsync = batch.SetAddAsync(string.Format(keyFormat, row.Field<int>("Id")), row.Field<int>("Value"));
    addTasks.Add(addAsync);
}
batch.Execute();
Task[] tasks = addTasks.ToArray();
Task.WaitAll(tasks);

我没有注意到任何明显的时差(实际上,我希望批处理方法会更快):对于大约250K的插入,流水处理大约需要7秒,而批处理大约需要8秒。

阅读有关流水线的文档,

“使用流水线使我们能够立即将两个请求都发送到网络上,从而消除了大部分延迟。此外,它还有助于减少数据包碎片:单独发送20个请求(等待每个响应)将至少需要20个数据包,但发送了20个请求管道中的数据包可以容纳更少的数据包(甚至可能只有一个)。”

对我来说,这听起来很像批处理行为。我想知道两者之间是否有很大的不同,因为通过简单检查,procmon我发现TCP Send两个版本的s
数量几乎相同。


问题答案:

在后台,SE.Redis做了很多工作来避免数据包碎片,因此在您的情况下它非常相似也就不足为奇了。批处理和扁平管道之间的主要区别是:

  • 批将永远不会与同一多路复用器上的竞争操作交错(尽管它可以在服务器上交错;为避免需要使用multi/ exec事务或Lua脚本)
  • 批次将始终避免出现数据包过小的机会,因为它可以提前知道所有数据
  • 但是同时,必须先完成整个批处理,然后才能发送任何内容,因此这需要更多的内存缓冲,并且可能人为地引入延迟

在大多数情况下,通过避免批处理,您会做得更好,因为SE.Redis 只需添加工作即可 自动完成 大部分工作。

最后一点;如果要避免局部开销,一种最后的方法可能是:

redisDB.SetAdd(string.Format(keyFormat, row.Field<int>("Id")),
    row.Field<int>("Value"), flags: CommandFlags.FireAndForget);

这将一切发送出去,既不等待响应也不分配不完整的Tasks来表示将来的值。你可能想要做的事就像Ping在年底 没有
发射后不管,检查服务器仍然跟你说话。请注意,使用即发即弃确实意味着您不会注意到任何报告的服务器错误。



 类似资料:
  • 本文向大家介绍StackExchange.Redis 流水线和多路复用,包括了StackExchange.Redis 流水线和多路复用的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 问题内容: 当我们在Redis中使用事务时,它基本上流水线化了事务中的所有命令。当EXEC被触发时,所有命令将一起执行,从而始终保持多个命令的原子性。 这与流水线不一样吗? 流水线和事务有何不同?另外,为什么Redis的单线程性质不足以满足要求?为什么我们明确需要流水线/事务? 问题答案: 流水线主要是网络优化。从本质上讲,这意味着客户端可以缓冲一堆命令并将它们一次性发送到服务器。不能保证在事务中

  • 我的服务器将响应发送到客户端或将消息转发到另一个客户端取决于消息内容。我需要使用8字节的消息:大括号之间的6个加密字节,例如: 其中0x3c表示<符号作为开始帧标记,0x3e表示>符号作为结束帧标记。 所以我得到4字节的有效负载(0x02,0x03,0x04,0x05)。 我已经编写了一个FrameDecoder,但现在我不能决定是否删除大括号字节: 我想写干净的代码,大括号只是框架标记,所以它们

  • 主要内容:实例,实例,实例,实例,实例,实例关键词:流水线,乘法器 硬件描述语言的一个突出优点就是指令执行的并行性。多条语句能够在相同时钟周期内并行处理多个信号数据。 但是当数据串行输入时,指令执行的并行性并不能体现出其优势。而且很多时候有些计算并不能在一个或两个时钟周期内执行完毕,如果每次输入的串行数据都需要等待上一次计算执行完毕后才能开启下一次的计算,那效率是相当低的。流水线就是解决多周期下串行数据计算效率低的问题。 流水线 流水线的基

  • 问题内容: 我必须用Java实现HTTP客户端,并且出于我的需要,似乎最有效的方法是实现HTTP管道(按照RFC2616)。 顺便说一句,我想管道POST。(我也不在谈论多路复用。我在谈论流水线,即在接收到任何HTTP请求的响应之前,通过一个连接发送许多请求) 我找不到明确声明其支持流水线的第三方库。但是我可以使用例如Apache HTTPCore 来构建这样的客户端,或者如果需要的话,可以自己构

  • 我有一个要求,我想在下面的场景中使用Spring批处理框架。 我有一个在交易日期列上分区的表。我想使用Spring批处理框架的阅读器、处理器和写入器来处理该表的记录。我想做的是根据交易日期创建单独的线程进行读取、写入和处理。假设有4个交易日期,那么我想为单独的交易日期创建4个单独的线程。在每个线程中,阅读器将从该交易日期的表中读取记录,在处理器中丰富记录,然后在写入器中发布/写入。 我是Sprin