"gewoon" is een zeer relatieve term en is niet echt logisch zonder meer context, met name:hoe groot zijn deze payloads?
echter, om een paar punten te verduidelijken om u te helpen onderzoeken:
- het is niet nodig om een
IDatabase
te vergrendelen tenzij dat puur voor uw eigen doeleinden is; SE.Redis houdt zich intern bezig met threadveiligheid en is bedoeld om te worden gebruikt door concurrerende threads - op dit moment omvat uw timing hiervan alle serialisatiecode (
JsonConvert.SerializeObject
); dit zal oplopen, vooral als je objecten groot zijn; om een fatsoenlijke maat te krijgen, raad ik je ten zeerste aan om de serialisatie- en redis-tijden afzonderlijk te timen - de
batch.Execute()
methode gebruikt een pijplijn-API en wacht niet op reacties tussen aanroepen, dus:de tijd die u ziet is niet het cumulatieve effect van latentie; dat laat alleen de lokale CPU (voor serialisatie), netwerkbandbreedte en server-CPU over; de tools van de clientbibliotheek kunnen geen van deze dingen beïnvloeden - er is een
StringSet
overbelasting die eenKeyValuePair<RedisKey, RedisValue>[]
accepteert; je zou kies ervoor om dit te gebruiken in plaats van een batch, maar het enige verschil hier is dat het de varadicMSET
is in plaats van meerdereSET
; hoe dan ook, je blokkeert de verbinding voor andere bellers voor de duur (aangezien het doel van batch is om de opdrachten aaneengesloten te maken) - je eigenlijk niet moet
CreateBatch
. gebruiken hier, vooral omdat je de database vergrendelt (maar ik stel toch voor dat je dit niet hoeft te doen); het doel vanCreateBatch
is om een reeks opdrachten opeenvolgend . te maken , maar ik zie niet dat je dit hier nodig hebt; je zou gewoon_database.StringSetAsync
. kunnen gebruiken voor elk commando om de beurt, wat ook hebben het voordeel dat u serialisatie parallel aan . zou uitvoeren de vorige opdracht wordt verzonden - het zou u toestaan om serialisatie (CPU-gebonden) en redis ops (IO-gebonden) te overlappen zonder enig werk, behalve om deCreateBatch
te verwijderen telefoongesprek; dit betekent ook dat u de verbinding van andere bellers niet monopoliseert
Dus; de eerste wat ik zou doen is verwijderen wat code:
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());
}
Het tweede wat ik zou doen zou zijn om de serialisatie apart van het redis-werk te timen.
Het derde wat ik zou doen is kijken of ik kan serialiseren naar een MemoryStream
in plaats daarvan idealiter een die ik kan hergebruiken - om de string
. te vermijden alocatie en UTF-8-codering:
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));
}
}