"apenas" é um termo muito relativo e não faz sentido sem mais contexto, em particular:quão grandes são essas cargas?
no entanto, para esclarecer alguns pontos para ajudá-lo a investigar:
- não há necessidade de bloquear um
IDatabase
a menos que seja puramente para seus próprios propósitos; O SE.Redis lida com a segurança de threads internamente e deve ser usado por threads concorrentes - no momento, seu tempo para isso incluirá todo o código de serialização (
JsonConvert.SerializeObject
); isso aumentará, especialmente se seus objetos são grandes; para obter uma medida decente, sugiro fortemente que você cronometre os tempos de serialização e redis separadamente - o
batch.Execute()
O método usa uma API de pipeline e não espera respostas entre as chamadas, então:o horário que você está vendo é não o efeito cumulativo da latência; que deixa apenas CPU local (para serialização), largura de banda de rede e CPU do servidor; as ferramentas da biblioteca cliente não podem afetar nada disso - há um
StringSet
sobrecarga que aceita umKeyValuePair<RedisKey, RedisValue>[]
; você poderia opte por usar isso em vez de um lote, mas a única diferença aqui é que é oMSET
varadic em vez de múltiplosSET
; de qualquer forma, você estará bloqueando a conexão para outros chamadores durante a duração (já que o objetivo do lote é tornar os comandos contíguos) - você não na verdade precisa usar
CreateBatch
aqui, especialmente já que você está bloqueando o banco de dados (mas ainda sugiro que você não precise fazer isso); o objetivo deCreateBatch
é fazer uma sequência de comandos sequencial , mas não vejo que você precise disso aqui; você pode simplesmente usar_database.StringSetAsync
para cada comando, o que também tem a vantagem de estar executando a serialização em paralelo com o comando anterior sendo enviado - ele permitiria sobrepor a serialização (limite da CPU) e operações de redis (vinculado ao IO) sem nenhum trabalho, exceto para excluir oCreateBatch
ligar; isso também significa que você não monopoliza a conexão de outros chamadores
Então; o primeiro coisa que eu faria seria remover algum 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());
}
A segunda coisa que eu faria seria cronometrar a serialização separadamente para o trabalho redis.
A terceira coisa que eu faria seria ver se consigo serializar para um
MemoryStream
em vez disso, de preferência um que eu possa reutilizar - para evitar a string
alocação e codificação 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));
}
}