使用 DataContractSerializer 慢速序列化 WCF 响应

Posted

技术标签:

【中文标题】使用 DataContractSerializer 慢速序列化 WCF 响应【英文标题】:Slow serialization of WCF response using DataContractSerializer 【发布时间】:2013-09-10 14:11:29 【问题描述】:

我有一个 WCF 服务,它执行搜索并向客户端返回一个相当复杂的对象列表。这是一个 EAV 系统,因此返回的每个实体都有一个附加值列表,其大小取决于实体蓝图。

在我的测试搜索中,我已通过日志记录确认,几乎在每种情况下,实际搜索都需要不到一秒钟的时间才能完成。在将响应返回给客户端之前,我做的最后一件事是记录处理已完成。

不幸的是,客户在我完成后 15-20 秒后才收到响应。总响应大小约为 250kb,非常小。这正在通过 LAN 传输,我已尝试禁用防火墙和防病毒软件以确保两者都不会干扰。

但是,我注意到,如果响应非常小,例如通过删除附加到每个实体的字段,响应会更快地通过。我还尝试单步执行服务的本地托管 (IIS) 副本,在通过最终的 return 语句后,仍然需要 15 秒才能到达本地客户端应用程序。

我正在使用 basicHttpBinding,因为该服务将被 .Net 和 php 客户端使用。

那么,任何人都可以提出一种方法来确认情况确实如此吗?以及如何解决极其缓慢的序列化时间?

编辑:

为了澄清,我用 [DataContract] 属性标记了每个类,用 [DataMember] 标记了每个属性 - 当我返回数据时,WCF 正在处理序列化。在这种情况下,它是一个实体类型的列表(一个包含值列表的自定义类。

编辑 2:

我测试了 DataContractSerializer 的速度,将包含 65 个返回实体的列表写入一个简单的内存流大约需要 15 秒。这看起来很荒谬,我不确定是什么改变了让它变得如此缓慢。

【问题讨论】:

你使用什么代码进行序列化?您是否使用 Fiddler 查看第一个字节何时进入。您在序列化什么类?你在序列化一个对象列表吗? 编辑了问题以包含您要求的信息。 哦,我还没有尝试过 Fiddler - 现在会调查一下。 我们可以排除 linq 查询吗?当您遍历它时,正在评估 Linq 查询;所以长序列化可能是由于从数据库中提取实体的时间过长,因为它必须在序列化期间进行评估。 恐怕也不是这样 - 我使用 sprocs 是为了与我一起工作的 PHP 人员的利益,我还缓存了所有实体,因此加载它们只需要毫秒。 【参考方案1】:

我已经想通了,这很尴尬。

在测试 DataContractSerializer 的速度时,我使用了从搜索中返回的 65 种产品的列表。我决定将所有产品(大约 600 个)加载到数据库中,然后将它们序列化到内存中,但是遇到了一些内存不足的异常,因此开始将结果写入文本文件。

原来文本文件是 1.5GB,大约是整个数据库大小的 3 倍。序列化耗时 17 秒。所以实际上,它做得非常好。发生的事情是每个产品都可以有一个附加实体的列表,并且这些实体也被加载了。因为它们是序列化的,所以这些实体是重复的,它们在数据库中只存在一次。

除了删除大量客户不需要的元数据外,我还设法将 50 种产品的列表(原为 194MB)缩小到仅 3MB。 (更新:本周末我将 1.5GB 列表降至 66MB)。

故事的寓意?倾听社区。其他人都告诉我 DataContractSerializer 有多快,所以当我觉得它很慢时,我应该责怪自己而不是 DataContractSerializer。

更新:

我花了一些时间试图弄清楚为什么这是一个突然的问题。答案在于 EAV 系统的性质——附加到任何实体的数据列表是动态的。我最初只在请求单个实体时才加载字段数据 - 为了速度,多个实体只加载了最低限度。在我实现缓存之后,我将其更改为加载所有字段数据,但由于复杂的数据模型和大量实体,我没有预料到这会对数据量产生多大的影响。真的,我不应该对我请求的数据量做出任何假设。

【讨论】:

【参考方案2】:

您必须使用DataContractSerializer 吗?我发现DataContractSerializer在发送大量数据时非常慢,性能损失不是在序列化时而是在反序列化时。

我们切换到二进制序列化,速度更快,但它可能与您的 PHP 客户端不兼容。您可以编写一个可由客户端重用的组件,为您处理反序列化,但您将对所有非 .net 客户端进行此操作。

【讨论】:

以上是关于使用 DataContractSerializer 慢速序列化 WCF 响应的主要内容,如果未能解决你的问题,请参考以下文章

使用 DataContractSerializer 时设置属性的初始值

使用 DataContractSerializer 和 XmlDictionaryWriter 序列化 JObject 后崩溃

在原语列表上使用 DataContractSerializer 的自定义元素名称

使用 DataContractSerializer 的接口中的显式类型

使用 DataContractSerializer 序列化没有命名空间的对象

如何使用 DataContractSerializer 从 XMLDocument 的单个节点反序列化?