"simplemente" es un término muy relativo y realmente no tiene sentido sin más contexto, en particular:¿qué tan grandes son estas cargas útiles?
sin embargo, para aclarar algunos puntos que lo ayudarán a investigar:
- no hay necesidad de bloquear una
IDatabase
a menos que sea puramente para sus propios fines; SE.Redis se ocupa de la seguridad de subprocesos internamente y está diseñado para ser utilizado por subprocesos de la competencia - por el momento, su momento de esto incluirá todo el código de serialización (
JsonConvert.SerializeObject
); esto se sumará, especialmente si tus objetos son grandes; para obtener una medida decente, le sugiero enfáticamente que cronometre la serialización y el tiempo de redis por separado - el
batch.Execute()
utiliza una API de canalización y no espera respuestas entre llamadas, por lo que:la hora que está viendo es no el efecto acumulativo de la latencia; eso deja solo la CPU local (para la serialización), el ancho de banda de la red y la CPU del servidor; las herramientas de la biblioteca del cliente no pueden afectar ninguna de esas cosas - hay un
StringSet
sobrecarga que acepta unKeyValuePair<RedisKey, RedisValue>[]
; usted podría elija usar esto en lugar de un lote, pero la única diferencia aquí es que es elMSET
varadic en lugar de múltiplesSET
; de cualquier manera, bloqueará la conexión para otras personas que llamen durante el tiempo (ya que el propósito del lote es hacer que los comandos sean contiguos) - usted no en realidad necesita usar
CreateBatch
aquí, especialmente ya que está bloqueando la base de datos (pero aún sugiero que no necesita hacer esto); el propósito deCreateBatch
es hacer una secuencia de comandos secuencial , pero no veo que necesites esto aquí; simplemente podría usar_database.StringSetAsync
para cada comando a su vez, que también tiene la ventaja de que estaría ejecutando la serialización en paralelo a el comando anterior que se envió:le permitiría superponer la serialización (vinculado a la CPU) y las operaciones de redis (vinculado a IO) sin ningún trabajo, excepto eliminar elCreateBatch
llamar; esto también significará que no monopolizas la conexión de otras personas que llaman
Asi que; el primero lo que haría sería eliminar algún código:
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());
}
Lo segundo que haría sería cronometrar la serialización por separado del trabajo de redis.
Lo tercero que haría sería ver si puedo serializar a un MemoryStream
en cambio, idealmente uno que pueda reutilizar, para evitar la string
asignación y codificación 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));
}
}