Моя проблема очень похожа на проблему в этом вопросе: проблема одновременной производительности protobuf-net в TakeLock. Разница в том, что в нашем случае мы используем данные CompressedSerializer и Deserializing. Следующий код вызывается из 8 разных потоков (по 8-ядерному процессору) каждый раз, когда нам нужно десериализовать данные.
var result = new ProtoCompressedSerializer().Deserialize<Dictionary<string, CustomStruct>>(...)
Вот результат ANTS Performance Profiler:
Первый узел в графе - это наш метод, который вызывает десериализацию с использованием приведенного выше кода. Число слева в каждом поле - это время в секундах, а справа - количество попаданий. Как вы видите, RunTimeTypeModel.TakeLock занимает много времени. В связанном выше вопросе предложение заключалось в прекомпиляции модели. Возможно ли это для CompressedSerializer и метода Deserialize? С точки зрения производительности лучше ли создавать один сериализатор и делиться им среди всех потоков? Это поточно-безопасный?
Попробовав несколько опций и сравнив их производительность с помощью Performance Profiler, я пришел к выводу, что Dictionary<T,K>
неправильно поддерживается ProtoBuf-net и даже инициализирует сериализатор заранее, это не поможет.
Решение состоит в том, чтобы завернуть словарь в новый класс как единственный элемент данных. Это не только улучшит производительность в несколько раз, мы увидим улучшение в 3 раза, но и практически исключаем использование TakeLock и связанные с этим проблемы с таймаутом.
Пример:
[Serializable]
[ProtoContract]
[DataContract]
public class ModelADict
{
[ProtoMember(1)]
[DataMember]
public Dictionary<string, ModelA> sub { get; set; }
public ModelADict()
{
sub = new Dictionary<string, ModelA>();
}
}