"Nur" ist ein sehr relativer Begriff und macht ohne mehr Kontext keinen Sinn, insbesondere:Wie groß sind diese Nutzlasten?
Um jedoch einige Punkte zu klären, die Ihnen bei der Untersuchung helfen:
- Es besteht keine Notwendigkeit, eine
IDatabase
zu sperren es sei denn, dies dient ausschließlich Ihren eigenen Zwecken; SE.Redis befasst sich intern mit der Thread-Sicherheit und soll von konkurrierenden Threads verwendet werden - Im Moment umfasst Ihr Timing dafür den gesamten Serialisierungscode (
JsonConvert.SerializeObject
); das wird sich summieren, besonders wenn Ihre Objekte groß sind; Um ein anständiges Maß zu erhalten, empfehle ich Ihnen dringend, die Zeit der Serialisierung und die Redis-Zeit separat festzulegen - der
batch.Execute()
-Methode verwendet eine Pipeline-API und wartet nicht auf Antworten zwischen Aufrufen, also:Die Zeit, die Sie sehen, ist nicht der kumulative Effekt der Latenz; das lässt nur die lokale CPU (für die Serialisierung), die Netzwerkbandbreite und die Server-CPU übrig; die Tools der Client-Bibliothek können diese Dinge nicht beeinflussen - es gibt ein
StringSet
-Überladung, die einKeyValuePair<RedisKey, RedisValue>[]
akzeptiert; Sie könnten entscheiden Sie sich dafür, dies anstelle eines Stapels zu verwenden, aber der einzige Unterschied besteht darin, dass es sich um das varadischeMSET
handelt anstatt mehrereSET
; In jedem Fall blockieren Sie die Verbindung für andere Anrufer für die Dauer (da der Zweck von Batches darin besteht, die Befehle zusammenhängend zu machen) - Sie eigentlich nicht müssen
CreateBatch
verwenden hier besonders da Sie die Datenbank sperren (aber ich schlage immer noch vor, dass Sie dies nicht tun müssen); der Zweck vonCreateBatch
besteht darin, eine Folge von Befehlen sequenziell zu machen , aber ich sehe nicht, dass Sie das hier brauchen; Sie könnten einfach_database.StringSetAsync
verwenden für jeden Befehl der Reihe nach, was auch würde haben den Vorteil, dass Sie die Serialisierung parallel zu ausführen würden der vorherige Befehl gesendet wird - es würde Ihnen erlauben, die Serialisierung (CPU-gebunden) und Redis-Operationen (IO-gebunden) ohne Arbeit zu überlappen, außer denCreateBatch
zu löschen Forderung; dies bedeutet auch, dass Sie die Verbindung anderer Anrufer nicht monopolisieren
So; die erste Was ich tun würde, wäre entfernen etwas 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());
}
Das zweite, was ich tun würde, wäre, die Serialisierung getrennt von der Redis-Arbeit zu timen.
Das dritte, was ich tun würde, wäre zu sehen, ob ich zu einem MemoryStream
serialisieren kann stattdessen idealerweise eine, die ich wiederverwenden kann - um den string
zu vermeiden Zuordnung und UTF-8-Kodierung:
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));
}
}