"bare" er et meget relativt begreb, og det giver ikke rigtig mening uden mere kontekst, især:hvor store er disse nyttelaster?
dog for at præcisere et par punkter for at hjælpe dig med at undersøge:
- der er ingen grund til at låse en
IDatabase
medmindre det udelukkende er til dine egne formål; SE.Redis beskæftiger sig med gevindsikkerhed internt og er beregnet til at blive brugt af konkurrerende gevind - i øjeblikket vil din timing af dette inkludere al serialiseringskoden (
JsonConvert.SerializeObject
); dette vil tilføje op, især hvis dine genstande er store; For at få et anstændigt mål, foreslår jeg kraftigt, at du tider serialiserings- og genoptagelsestiderne separat batch.Execute()
metoden bruger en pipeline API og venter ikke på svar mellem opkald, så:tidspunktet du ser er ikke den kumulative effekt af latens; der kun efterlader lokal CPU (til serialisering), netværksbåndbredde og server-CPU; klientbiblioteksværktøjerne kan ikke påvirke nogen af disse ting- der er et
StringSet
overbelastning, der accepterer etKeyValuePair<RedisKey, RedisValue>[]
; du kunne vælge at bruge dette i stedet for en batch, men den eneste forskel her er, at det er varadicMSET
i stedet for flereSET
; uanset hvad, vil du blokere forbindelsen for andre opkaldere i varigheden (da formålet med batch er at gøre kommandoerne sammenhængende) - det gør du ikke faktisk skal bruge
CreateBatch
her, især da du låser databasen (men jeg foreslår stadig, at du ikke behøver at gøre dette); formålet medCreateBatch
er at lave en sekvens af kommandoer sekventiel , men jeg kan ikke se, at du har brug for dette her; du kunne bare bruge_database.StringSetAsync
for hver kommando efter tur, hvilket også ville har den fordel, at du vil køre serialisering parallelt med den forrige kommando, der sendes - den ville tillade dig at overlappe serialisering (CPU bundet) og redis ops (IO bundet) uden noget arbejde bortset fra at sletteCreateBatch
opkald; dette vil også betyde, at du ikke monopoliserer forbindelsen fra andre opkaldere
Så; den første ting, jeg ville gøre, ville være at fjerne noget kode:
private static StackExchange.Redis.IDatabase _database;
static JsonSerializerSettings _redisJsonSettings = new JsonSerializerSettings {
ContractResolver = new SerializeAllContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
public void SetAll<T>(Dictionary<string, T> data, int cacheTime)
{
TimeSpan expiration = new TimeSpan(0, cacheTime, 0);
var list = new List<Task<bool>>();
foreach (var item in data)
{
string serializedObject = JsonConvert.SerializeObject(
item.Value, Formatting.Indented, _redisJsonSettings);
list.Add(_database.StringSetAsync(item.Key, serializedObject, expiration));
}
Task.WhenAll(list.ToArray());
}
Den anden ting, jeg ville gøre, ville være at time serialiseringen separat til redis-arbejdet.
Den tredje ting, jeg ville gøre, ville være at se, om jeg kan serialisere til en MemoryStream
i stedet, ideelt set en, som jeg kan genbruge - for at undgå string
alocation og UTF-8 encode:
using(var ms = new MemoryStream())
{
foreach (var item in data)
{
ms.Position = 0;
ms.SetLength(0); // erase existing data
JsonConvert.SerializeObject(ms,
item.Value, Formatting.Indented, _redisJsonSettings);
list.Add(_database.StringSetAsync(item.Key, ms.ToArray(), expiration));
}
}