我试图在尽可能短的时间内插入大量( - )数量的元素,我尝试了这两种选择:
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秒。
阅读有关流水线的文档,
&#34;使用流水线操作可以让我们将两个请求都发送到网络上 立即消除大部分延迟。此外,它也 有助于减少数据包碎片:单独发送20个请求 (等待每个响应)将需要至少20个包,但是20个 在管道中发送的请求可能适合更少的数据包(也许 甚至只有一个。&#34;
对我而言,这听起来很像批处理行为。我想知道幕后是否存在两者之间的任何重大差异,因为通过procmon
进行简单检查,我发现两个版本的TCP Send
数量几乎相同。
答案 0 :(得分:26)
在幕后,SE.Redis尝试避免数据包碎片做了相当多的工作,因此在您的情况下它非常相似并不奇怪。批处理和扁平流水线之间的主要区别是:
multi
/ exec
事务或Lua脚本)在大多数情况下,您可以通过避免批处理来做得更好,因为SE.Redis只需添加工作即可实现自动的大部分功能。
作为最后的说明;如果你想避免本地开销,最后一种方法可能是:
redisDB.SetAdd(string.Format(keyFormat, row.Field<int>("Id")),
row.Field<int>("Value"), flags: CommandFlags.FireAndForget);
这会发送所有内容,既不等待响应也不分配不完整的Task
来表示未来的值。您可能希望在结束时执行类似Ping
的操作,而无需点击,以检查服务器是否还在与您通话。请注意,使用“即发即弃”确实意味着您不会注意到报告的任何服务器错误。