„tylko” jest terminem bardzo względnym i nie ma sensu bez większego kontekstu, w szczególności:jak duże są te ładunki?
jednak, aby wyjaśnić kilka punktów, które pomogą Ci zbadać:
- nie ma potrzeby blokowania
IDatabase
chyba że służy to wyłącznie twoim własnym celom; SE.Redis zajmuje się wewnętrznie bezpieczeństwem wątków i jest przeznaczony do użytku przez konkurencyjne wątki - w tej chwili czas wykonania tej czynności będzie obejmował cały kod serializacji (
JsonConvert.SerializeObject
); to się zsumuje, zwłaszcza jeśli twoje przedmioty są duże; aby uzyskać przyzwoitą miarę, zdecydowanie sugeruję, abyś czasy serializacji i redis były oddzielnie batch.Execute()
Metoda wykorzystuje API potoku i nie czeka na odpowiedzi między wywołaniami, więc:czas, który widzisz, to nie skumulowany efekt utajenia; to pozostawia tylko lokalny procesor (do serializacji), przepustowość sieci i procesor serwera; narzędzia biblioteki klienta nie mogą wpływać na żadną z tych rzeczy- istnieje
StringSet
przeciążenie, które akceptujeKeyValuePair<RedisKey, RedisValue>[]
; mogłeś zdecydować się na użycie tego zamiast partii, ale jedyną różnicą jest to, że jest to varadicMSET
zamiast wielokrotnegoSET
; tak czy inaczej, będziesz blokować połączenie dla innych rozmówców na czas (ponieważ celem partii jest, aby polecenia były ciągłe) - nie właściwie trzeba użyć
CreateBatch
tutaj, zwłaszcza ponieważ blokujesz bazę danych (ale nadal sugeruję, że nie musisz tego robić); celCreateBatch
jest wykonanie sekwencji poleceń sekwencyjnych , ale nie widzę, że potrzebujesz tego tutaj; możesz po prostu użyć_database.StringSetAsync
dla każdego polecenia po kolei, co również mieć tę zaletę, że będziesz uruchamiać serializację równolegle z poprzednie wysyłane polecenie - pozwoliłoby to na nakładanie się serializacji (związane z procesorem) i operacji redis (związane z IO) bez żadnej pracy, z wyjątkiem usunięciaCreateBatch
połączenie; oznacza to również, że nie zmonopolizujesz połączenia od innych rozmówców
Więc; pierwszy co bym zrobił, to usunąć jakiś kod:
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());
}
Drugą rzeczą, którą bym zrobił, to zsynchronizowanie serializacji oddzielnie z pracą nad redisem.
Trzecią rzeczą, którą bym zrobił, byłoby sprawdzenie, czy mogę serializować do MemoryStream
zamiast tego najlepiej taki, którego mogę użyć ponownie - aby uniknąć string
alokacja i kodowanie 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));
}
}