C# 使用C将非常大的项目列表序列化到Azure blob存储中#

C# 使用C将非常大的项目列表序列化到Azure blob存储中#,c#,azure,serialization,protocol-buffers,capnproto,C#,Azure,Serialization,Protocol Buffers,Capnproto,我有一个很大的对象列表,以后需要存储和检索。列表将始终作为一个单元使用,列表项不会单独检索。该列表包含约7000个项目,总容量约为1GB,但很容易升级到10倍或更多 我们一直在使用BinaryFormatter.Serialize()进行序列化(System.Runtime.serialization.Formatters.Binary.BinaryFormatter)。然后,此字符串作为blob上载到Azure blob存储。我们发现它通常是快速高效的,但由于我们使用更大的文件大小进行测试,抛

我有一个很大的对象列表,以后需要存储和检索。列表将始终作为一个单元使用,列表项不会单独检索。该列表包含约7000个项目,总容量约为1GB,但很容易升级到10倍或更多

我们一直在使用
BinaryFormatter.Serialize()
进行序列化(
System.Runtime.serialization.Formatters.Binary.BinaryFormatter
)。然后,此字符串作为blob上载到Azure blob存储。我们发现它通常是快速高效的,但由于我们使用更大的文件大小进行测试,抛出了一个
OutOfMemoryException
,因此它变得不充分。据我所知,虽然我使用的是流,但我的问题是,
BinaryFormatter.Serialize()
方法必须首先将所有内容序列化到内存中,然后才能上载blob,从而导致异常

二进制序列化程序如下所示:

public void Upload(object value, string blobName, bool replaceExisting)
{
    CloudBlockBlob blockBlob = BlobContainer.GetBlockBlobReference(blobName);
    var formatter = new BinaryFormatter()
    {
        AssemblyFormat = FormatterAssemblyStyle.Simple,
        FilterLevel = TypeFilterLevel.Low,
        TypeFormat = FormatterTypeStyle.TypesAlways
    };

    using (var stream = blockBlob.OpenWrite())
    {
        formatter.Serialize(stream, value);
    }
}
OutOfMemoryException发生在格式化程序.Serialize(流,值)行上

因此,我尝试使用不同的协议,协议缓冲区。我尝试在Nuget软件包protobuf net和Google.protobuf中使用这两种实现,但序列化速度非常慢(大约30分钟),而且据我所知,protobuf没有针对大于1MB的数据进行优化。所以,我回到绘图板,遇到了Cap'n Proto,它承诺通过使用内存映射来解决我的速度问题。我试图使用@marc gravell的C#绑定,但我在实现序列化程序时遇到了一些困难,因为该项目还没有完整的文档。此外,我不能100%确定Cap'n Proto是否是协议的正确选择,但我正在努力在网上找到任何替代建议


我如何将一个非常大的项目集合序列化到blob存储中,而不碰到内存问题,并且以一种相当快的方式?

也许您应该切换到JSON

使用JSON序列化程序,您可以在文件之间进行流式传输,并逐段(在读取文件时)进行序列化/反序列化

您的对象会很好地映射到JSON吗

这就是我用来获取NetworkStream并将其放入Json对象的内容

private静态异步任务进程jsonresponse(httpresponsemessageresponse)
{
//打开来自网络的流
使用(var s=await ProcessResponseStream(response).ConfigureAwait(false))
{
使用(var sr=新的StreamReader)
{
使用(var reader=newjsontextreader(sr))
{
var serializer=newjsonserializer{DateParseHandling=DateParseHandling.None};
返回序列化程序。反序列化(读取器);
}
}
}
}
此外,还可以GZip流以减少文件传输时间。我们直接流式传输到gzip JSON,然后再返回


Edit,虽然这是一个反序列化,但同样的方法应该适用于序列化

JSON序列化也可以工作,正如前面的海报所提到的,虽然一个列表足够大,但这也会导致抛出
OutOfMemoryException
异常,因为字符串太大,无法放入内存。如果您的对象是一个列表,您可能可以通过分段序列化来解决这个问题,但是如果您对二进制序列化没有意见,那么一种更快/更低内存的方法就是使用序列化


Protobuf具有并需要更小的内存占用,但代价是它不能被人类读取。这是一个很好的C#实现。和。在某些情况下,您甚至可以GZip Protobuf序列化字节并节省更多空间

将批上载到多个blob,而不是一次序列化所有内容?谢谢,这是我正在考虑的一个选项。每个列表在我们的域中已经是一块了,所以blob会失去一些上下文,这会使事情变得复杂一些。好的建议,但是,我会给它一个尝试,如果没有任何其他协议或方法的建议。