提问人:MrBott_a 提问时间:1/13/2023 最后编辑:MrBott_a 更新时间:1/13/2023 访问量:120
我可以使用 protobuf-net 将 ConcurrentDictionaries 序列化和反序列化为同一个文件,然后读取它吗?
Can I use protobuf-net to serialize and deserialize ConcurrentDictionaries to the same file and then read it?
问:
因此,我正在开发一个海军模拟器的通信管理器,该模拟器管理通信并存储所有数据,我需要序列化以快速且每秒最多 10 次提交大型并发字典,我需要这样做的次数是可变的,因为这是我们实现重放功能的尝试,序列化的数量取决于模拟花费的时间。经过一番研究,我登陆了 protobuf-net,但我无法弄清楚。
我需要处理的对象是具有许多属性的非常复杂的类,其中一些是自定义类型,并且继承自从其他类继承的类。并发词典看起来像这样 我认为我唯一做对的是用属性装饰类。其余的我都想不通。ConcurrentDictionary<string, MyClass>
我需要多次序列化到同一个文件,然后读取该文件以重新创建 ConcurrentDictionaries。我尝试了不同的方法,但没有取得任何成功......我需要一个方向。
我认为问题在于我多次序列化到同一个文件,当我反序列化时,我只是将文件作为流提供给方法。我认为它试图读取整个文件并分解......Serializer.Deserialize
编辑:按照建议,我添加了更多细节来保护程序。
答:
您可以声明一个容器(结构或类),其中包含您的字典作为成员,然后序列化/反序列化此容器。下面是一个示例:
[ProtoContract]
struct MyDictionaries
{
[ProtoMember(1)]
public ConcurrentDictionary<string, int> A;
[ProtoMember(2)]
public ConcurrentDictionary<string, char> B;
}
public static void Main()
{
MyDictionaries dictionaries = new();
dictionaries.A = new();
dictionaries.A.TryAdd("A", 1);
dictionaries.A.TryAdd("B", 2);
dictionaries.B = new();
dictionaries.B.TryAdd("C", 'c');
dictionaries.B.TryAdd("D", 'd');
Console.WriteLine($"dictionaries.A: {String.Join(", ", dictionaries.A)}");
Console.WriteLine($"dictionaries.B: {String.Join(", ", dictionaries.B)}");
MemoryStream stream = new();
Serializer.Serialize(stream, dictionaries);
Console.WriteLine();
stream.Position = 0;
var deserialized = Serializer.Deserialize<MyDictionaries>(stream);
Console.WriteLine($"deserialized.A: {String.Join(", ", deserialized.A)}");
Console.WriteLine($"deserialized.B: {String.Join(", ", deserialized.B)}");
}
输出:
dictionaries.A: [A, 1], [B, 2]
dictionaries.B: [D, d], [C, c]
deserialized.A: [A, 1], [B, 2]
deserialized.B: [D, d], [C, c]
在线演示。
文档明确指出支持类型,源代码中也有类型。IDictionary<TKey,TValue>
ConcurrentDictionarySerializer
评论
dict1: [A, 1], [B, 2] dictX: [C, 3], [D, 4] dict1PD: [C, 3], [D, 4], [A, 1], [B, 2] dictXPD:
There is a bit to unpack here.
To serialize multiple independent objects to the same stream you can use / . This should allow you to serialize objects one after each other. See ProtoInclude for how to handle inheritance.Serializer.SerializeWithLengthPrefix
Serializer.DeserializeWithLengthPrefix
To serialize each object I would tend to prefer to convert the objects into a separate type that is only used for serialization. Sometimes called a Data Transfer Object or DTO. This lets you separate the concerns of serialization from all kinds of domain logic, at the cost of some duplication of code.
There are a few ways to manage size. One approach is to only change changes to state, not the entire state. Something similar is sometimes used for games, where you only need to record the user input to allow you to replay the entire game. Another approach is compression, since states probably do not change that much. LZ4 claims to be one of the faster algorithms around. You might also want to keep things in memory if possible, since even the fastest SSD is much slower than memory.
I would highly recommend setting up a simple test environment. I.e. start by serializing a simple object, continue with a complex object, a dictionary of complex objects, and so on. This is also a good opportunity to measure performance.
评论
Serializer.SerializeWithLengthPrefix
File.Open(path, FileMode.Append)
File.Create
评论
ConcurrentDictionary<string, MyClass>
ConcurrentDictionary<string, CustomClass>