我试图在尽可能短的时间内插入大量元素,我尝试了这两种选择:
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
两个版本都有。
在幕后,SE.Redis 做了相当多的工作来尝试避免数据包碎片,因此它与您的情况非常相似也就不足为奇了。批处理和扁平流水线之间的主要区别是:
- 批次永远不会与同一多路复用器上的竞争操作交错(尽管它可能在服务器上交错;为避免这种情况,您需要使用
multi
/exec
事务或 Lua 脚本)
- 批次将始终避免数据包尺寸过小的可能性,因为它提前知道所有数据
- 但与此同时,必须先完成整个批次,然后才能发送任何内容,因此这需要更多的内存缓冲,并可能人为地引入延迟
在大多数情况下,避免批处理会做得更好,因为 SE.Redis 实现了它的大部分功能自动地当简单地添加工作时。
最后一点;如果您想避免本地开销,最后一种方法可能是:
redisDB.SetAdd(string.Format(keyFormat, row.Field<int>("Id")),
row.Field<int>("Value"), flags: CommandFlags.FireAndForget);
这会发送所有内容,既不等待响应也不分配不完整的数据Task
s 代表未来值。你可能想做一些类似的事情Ping
在最后without即发即忘,检查服务器是否仍在与您通信。请注意,使用“即发即弃”确实意味着您不会注意到报告的任何服务器错误。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)