目前,您的代码正在使用同步 API (StringSet
),并由 10 个线程同时加载。这不会给 SE.Redis 带来明显的挑战 - 它在这里工作得很好。我suspect这确实是一个超时,服务器花费的时间比您希望处理某些数据的时间长,很可能也与服务器的分配器有关。那么,一种选择就是简单地稍微增加超时时间。不是很多...尝试 5 秒而不是默认的 1 秒。无论如何,大多数操作可能都运行得非常快。
关于加速:这里的一种选择是not wait- 即保持数据流水线化。如果您不满足于检查每条消息的错误状态,那么一种简单的方法是添加, flags: CommandFlags.FireAndForget
到你的结束StringSet
称呼。在我的本地测试中,这将 1M 示例的速度提高了 25%(我怀疑剩余的大部分时间实际上都花在了字符串序列化上)。
我在 10M 示例中遇到的最大问题就是开销使用 10M 示例- 特别是因为这需要大量的内存redis-server
和应用程序(以模拟您的设置)位于同一台计算机上。这会产生竞争性内存压力,例如托管代码中的 GC 暂停等。但也许更重要的是:开始做任何事情都需要很长时间。因此,我重构了代码以使用并行yield return
生成器而不是单个列表。例如:
static IEnumerable<Person> InventPeople(int seed, int count)
{
for(int i = 0; i < count; i++)
{
int f = 1 + seed + i;
var item = new Person
{
Id = f,
Name = Path.GetRandomFileName().Replace(".", "").Substring(0, appRandom.Value.Next(3, 6)) + " " + Path.GetRandomFileName().Replace(".", "").Substring(0, new Random(Guid.NewGuid().GetHashCode()).Next(3, 6)),
Age = f % 90,
Friends = ParallelEnumerable.Range(0, 100).Select(n => appRandom.Value.Next(1, f)).ToArray()
};
yield return item;
}
}
static IEnumerable<T> Batchify<T>(this IEnumerable<T> source, int count)
{
var list = new List<T>(count);
foreach(var item in source)
{
list.Add(item);
if(list.Count == count)
{
foreach (var x in list) yield return x;
list.Clear();
}
}
foreach (var item in list) yield return item;
}
with:
foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD).Batchify(1000))
在此,目的是Batchify
是为了确保我们不会因为每次操作之间花费大量时间而对服务器造成太大帮助 - 数据以 1000 为一组创建,并且每批都很快可用。
我还担心 JSON 性能,所以我改用 JIL:
public static string ToJSON<T>(this T obj)
{
return Jil.JSON.Serialize<T>(obj);
}
然后只是为了好玩,我将 JSON 工作移至批处理中(以便实际的处理循环:
foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD)
.Select(x => new { x.Id, Json = x.ToJSON() }).Batchify(1000))
这使时间缩短了一些,因此我可以在 3 分 57 秒内加载 10M,速度为 42,194 转。大部分时间实际上是应用程序内部的本地处理。如果我改变它以便每个线程加载same item ITEMS / THREADS
次,则变为 1 分 48 秒 - 速率为 92,592 转。
我不确定我是否真的回答了任何问题,但简短的版本可能只是“尝试更长的超时;考虑使用即发即弃”。