"juste" est un terme très relatif, et n'a pas vraiment de sens sans plus de contexte, en particulier :quelle est la taille de ces charges utiles ?
cependant, pour clarifier quelques points pour vous aider à enquêter :
- il n'est pas nécessaire de verrouiller une
IDatabase
à moins que ce ne soit uniquement à vos propres fins ; SE.Redis gère la sécurité des threads en interne et est destiné à être utilisé par des threads concurrents - pour le moment, votre timing inclura tout le code de sérialisation (
JsonConvert.SerializeObject
); cela s'additionnera, surtout si vos objets sont gros; pour obtenir une mesure décente, je vous suggère fortement de chronométrer les temps de sérialisation et de redis séparément - le
batch.Execute()
La méthode utilise une API de pipeline et n'attend pas les réponses entre les appels, donc :l'heure que vous voyez n'est pas l'effet cumulatif de la latence ; cela ne laisse que le processeur local (pour la sérialisation), la bande passante du réseau et le processeur du serveur ; les outils de la bibliothèque cliente n'ont aucun impact sur ces éléments - il existe un
StringSet
surcharge qui accepte unKeyValuePair<RedisKey, RedisValue>[]
; tu pourrais choisir d'utiliser ceci au lieu d'un lot, mais la seule différence ici est qu'il s'agit du varadicMSET
plutôt que plusieursSET
; dans tous les cas, vous bloquerez la connexion pour les autres appelants pendant la durée (puisque le but du lot est de rendre les commandes contiguës) - vous ne savez pas en fait besoin d'utiliser
CreateBatch
ici, surtout puisque vous verrouillez la base de données (mais je suggère toujours que vous n'avez pas besoin de le faire); le but deCreateBatch
est de rendre une séquence de commandes séquentielle , mais je ne vois pas que vous en ayez besoin ici ; vous pouvez simplement utiliser_database.StringSetAsync
pour chaque commande à son tour, ce qui serait aussi avoir l'avantage d'exécuter la sérialisation parallèlement à la commande précédente étant envoyée - cela vous permettrait de chevaucher la sérialisation (liée au processeur) et les opérations redis (liées à l'IO) sans aucun travail, sauf pour supprimer leCreateBatch
appel; cela signifie également que vous ne monopolisez pas la connexion des autres appelants
Alors; le premier chose que je ferais serait de supprimer du 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());
}
La deuxième chose que je ferais serait de chronométrer la sérialisation séparément du travail redis.
La troisième chose que je ferais serait de voir si je peux sérialiser en un MemoryStream
à la place, idéalement un que je peux réutiliser - pour éviter la string
alocation et encodage UTF-8 :
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));
}
}