在AppDomains之间共享数据

我有一个可以有多个AppDomain的进程。 每个AppDomain都会收集一些统计信息。 在指定的时间之后,我想累积这些统计信息并将它们保存到文件中。

一种方法是远程处理,我想避免。

我想到的唯一其他技术是将每个AppDomain的数据保存在一个文件中,并在一段特定时间后,其中一个AppDomain收集所有数据并累积它们。

但如果所有这些都可以在内存中完成,那么这将是理想的,而无需在AppDomains之间序列化信息的成本。 有人有主意吗?

避免序列化的唯一方法是使用派生自MarshalByRefObject的对象来表示您的数据,但在这种情况下,您仍然需要跨AppDomain边界进行编组的成本。 这可能还涉及重构/重写大部分代码。

假设无法通过引用进行编组,则必须在某个时候进行序列化。 它根本无法避免。 一种方法是使用Neil Barnwell建议,使用数据库,另一种方法是使用您自己建议的本地文件。

根据您的交付时间表和/或.NET 4.0采用可能或不可行的另一种方法是使用内存映射文件,请参阅.Net Framework 4.0:使用内存映射文件 。

可以在AppDomains之间共享数据而无需编组。 但这是一种相当黑客的方式。 您可以创建一个源数据对象,该对象在所有AppDomain之间通过引用共享。 这样,您可以将所有数据放入一个共享对象,而无需编组。 听起来太容易了吗?

首先要知道如何在没有编组的情况下在AppDomains之间共享数据。 为此,您可以通过Marshal.UnsafeAddrOfPinnedArrayElement获取数据源对象的对象地址。 然后将此IntPtr传递给对此感兴趣的所有AppDomain。 在目标AppDomain中,您需要将此IntPtr转换回对象引用,该对象引用可以完成JIT :: CastAny,如果从方法返回一个对象并将其指针推送到堆栈上,则完成该操作。

Viola您已经将对象作为AppDomains之间的普通指针共享,并且您获得了InvalidCastExceptions。 问题是您必须为所有AppDomains LoaderOptimization.MultiDomain设置,以确保定义共享数据类型的程序集作为AppDomain中性类型加载,该类型在所有AppDomain之间具有相同的Method Table指针。

您可以找到一个示例应用程序,它作为WMemoryProfiler的一部分完成此操作。 请参阅此链接以获取更详细的说明并下载示例代码的链接 。

基本代码是

[LoaderOptimization(LoaderOptimization.MultiDomain)] static public void Main(string[] args) { // To load our assembly appdomain neutral we need to use MultiDomain on our hosting and child domain // If not we would get different Method tables for the same types which would result in InvalidCastExceptions // for the same type. var other = AppDomain.CreateDomain("Test"+i.ToString(), AppDomain.CurrentDomain.Evidence, new AppDomainSetup { LoaderOptimization = LoaderOptimization.MultiDomain, }); // Create gate object in other appdomain DomainGate gate = (DomainGate)other.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(DomainGate).FullName); // now lets create some data CrossDomainData data = new CrossDomainData(); data.Input = Enumerable.Range(0, 10).ToList(); // process it in other AppDomain DomainGate.Send(gate, data); // Display result calculated in other AppDomain Console.WriteLine("Calculation in other AppDomain got: {0}", data.Aggregate); } } 

我倾向于说只使用远程处理。 将数据写入文件也需要序列化。 无论您使用哪种技术,序列化似乎几乎是不可避免的。 您必须使用某个通道将数据从一个应用程序域传输到另一个应用程序域,您必须序列化数据才能通过该通道。

避免序列化的唯一方法似乎是使用共享内存,这样两个应用程序域都可以访问数据而无需通过通道。 即使将数据从一个应用程序域的内存深度克隆到另一个内存中,其核心也就是二进制序列化(其结果不一定存储在连续的内存位置)。

我很感激您希望将其保留在内存中,但我的第一个建议是将数据写入数据库并从那里进行查询。 远程处理仍然是远程调用,这是使用数据库服务器的大部分“成本”来源,并且您必须构建事务处理以确保不丢失数据。 如果您写入SQL Server数据库,则可以准备好事务支持并等待您,并且查询速度快,速度快。