В момента вашият код използва синхронния API (StringSet
) и се зарежда от 10 нишки едновременно. Това няма да представлява значително предизвикателство за SE.Redis - тук работи добре. подозирам че това наистина е изчакване, при което сървърът е отнел повече време, отколкото бихте искали да обработи някои от данните, най-вероятно също свързани с разпределителя на сървъра. Една от възможностите е просто да увеличите малко времето за изчакване . Не много... опитайте 5 секунди вместо 1 секунда по подразбиране. Вероятно повечето от операциите работят много бързо.
По отношение на ускоряването:една от опциите тук е да не чакате - т.е. продължавайте да предавате данни. Ако сте доволни да не проверявате всяко съобщение за състояние на грешка, тогава един лесен начин да направите това е да добавите , 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;
}
с:
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))
Това намали времето малко повече, така че мога да заредя 10M за 3 минути 57 секунди, скорост от 42 194 оборота. Повечето от това време всъщност е локална обработка в приложението. Ако го променя така, че всяка нишка да зарежда същото елемент ITEMS / THREADS
пъти, след това това се променя на 1 минута 48 секунди - скорост от 92 592 оборота.
Не съм сигурен дали наистина съм отговорил на нещо, но кратката версия може да бъде просто „опитайте с по-дълго време за изчакване; помислете за използването на „запали и забрави“.