0

在 ASP.NET 应用程序中使用 HttpRuntime.Cache 时,从缓存中检索并随后更新的任何项目都将导致缓存对象也被更新(通过引用)。随后从缓存中读取将获得更新的值,这可能是不可取的。

关于这个主题有多个帖子,例如:

以只读方式读取 HttpRuntime.Cache 项

建议的解决方案是使用二进制序列化创建一个深拷贝克隆。

二进制序列化的问题在于它很慢(非常慢),而且我无法承受任何潜在的性能瓶颈。我已经研究过使用反射的深度复制,虽然这似乎性能更好,但使用我们复杂的 DTO 实现并不是一件容易的事。对此感兴趣的任何人都可能想看看以下简短的文章:

快速深度克隆

有没有人有任何缓存解决方案(如 AppFrabric / NCache 等)的经验,并且知道他们是否会直接解决这个问题?

提前致谢

格里夫

4

2 回答 2

4

NCache 和 AppFabric 等产品也在将对象存储到进程外缓存服务之前执行序列化。所以你仍然会受到序列化的影响,而且你会因为进程外(甚至可能通过网络)访问缓存服务中的序列化对象而进一步减慢速度。

在您的类上实现ICloneable以执行手动调整的深度复制将避免反射并且将优于二进制序列化,但如果您的 DTO 非常复杂,这可能不切实际。

更新以提供细节:

AppFabric 使用 NetDataContractSerializer 进行序列化(如此所述)。NetDataContractSerializer 可能比 BinaryFormatter 快一点,但它的性能通常在同一个范围内:http: //blogs.msdn.com/b/youssefm/archive/2009/07/10/comparing-the-performance-of -net-serializers.aspx

NCache 推出了他们自己的序列化程序,称为“紧凑序列化”。您需要在 DTO 类上实现他们的 ICompactSerializable 接口并手动读/写所有成员,或者让他们的客户端库检查您的类,然后在运行时发出自己的序列化代码来为您完成这项工作(这是一个当您的应用程序启动时,他们必须反映您的课程并发出自己的 MSIL)。我没有关于它们性能的数据,但可以肯定的是,它比执行反射的序列化程序 (BinaryFormatter/DataContractSerializer) 更快,并且可能与 protobuf、MessagePack 和其他避免过度反射的序列化程序处于同一性能领域。更多细节在这里

(我在一家公司(ScaleOut Software)工作,该公司与 NCache 位于同一空间,所以我可能应该更多地了解他们是如何做事的。ScaleOut 让您可以插入任何您想要的序列化程序——我们通常推荐Protobuf-netMessagePack,因为它们通常被认为是 .NET 序列化性能的卫冕冠军——如果您决定使用序列化程序制作深层副本,请务必仔细查看这两个。)

于 2014-05-14T00:05:20.887 回答
0

大多数缓存框架都依赖于序列化。

每次更改对象时都应考虑使缓存无效。

例如:

object Get(string key) 
{ 
    if (!Cache.Contains(key))
    {
        Cache[key] = GetDataFromDatabase(key);
    }
    return Cache[key];
}

void Invalidate(string key)
{
    Cache.Remove(key);
}

所以你可以这样做:

var myDto = Get(id);
myDto.SomeProperty = "changed";
myDto.Save();
Invalidate(id);
于 2014-05-14T02:40:45.550 回答