För närvarande använder din kod det synkrona API:et (StringSet
), och laddas av 10 trådar samtidigt. Detta kommer inte att innebära någon nämnvärd utmaning för SE.Redis - det fungerar alldeles utmärkt här. Jag misstänker att det verkligen är en timeout där servern har tagit längre tid än du skulle vilja att bearbeta en del av datan, troligen också relaterat till serverns allokator. Ett alternativ är alltså att helt enkelt öka timeouten lite . Inte mycket... försök 5 sekunder istället för standard 1 sekund. Förmodligen fungerar de flesta operationerna väldigt snabbt ändå.
När det gäller att påskynda det:ett alternativ här är att inte vänta - d.v.s. behålla pipeliningdata. Om du nöjer dig med att inte kontrollera varje enskilt meddelande för ett feltillstånd, är ett enkelt sätt att göra detta att lägga till , flags: CommandFlags.FireAndForget
till slutet av ditt StringSet
ringa upp. I mina lokala tester påskyndade detta 1M-exemplet med 25 % (och jag misstänker att mycket av resten av tiden faktiskt ägnas åt strängserialisering).
Det största problemet jag hade med 10M-exemplet var helt enkelt overheaden av att arbeta med 10M-exemplet - speciellt eftersom detta tar enorma mängder minne för både redis-server
och programmet, som (för att efterlikna din installation) finns på samma maskin. Detta skapar konkurrerande minnestryck, med GC-pauser etc i den hanterade koden. Men kanske ännu viktigare:det tar helt enkelt en evighet att börja göra någonting . Följaktligen ändrade jag koden för att använda parallell yield return
generatorer snarare än en enda lista. Till exempel:
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;
}
med:
foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD).Batchify(1000))
Här är syftet med Batchify
är att säkerställa att vi inte hjälper servern för mycket genom att ta avsevärd tid mellan varje operation - data uppfinns i batcher om 1000 och varje batch görs tillgänglig mycket snabbt.
Jag var också bekymrad över JSON-prestanda, så jag bytte till JIL:
public static string ToJSON<T>(this T obj)
{
return Jil.JSON.Serialize<T>(obj);
}
och sedan för skojs skull flyttade jag JSON-arbetet till batchningen (så att själva bearbetningsslingan :
foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD)
.Select(x => new { x.Id, Json = x.ToJSON() }).Batchify(1000))
Detta fick tiderna ner lite mer, så jag kan ladda 10M på 3 minuter och 57 sekunder, en hastighet på 42 194 rops. Det mesta av denna tid är faktiskt lokal bearbetning inuti applikationen. Om jag ändrar det så att varje tråd laddar samma objekt ITEMS / THREADS
gånger, då ändras detta till 1 minut 48 sekunder - en hastighet på 92 592 rops.
Jag är inte säker på om jag har svarat på något riktigt, men den korta versionen kan helt enkelt vara "försök med en längre timeout, överväg att använda eld-och-glöm".