在AppDomains之间共享数据

时间:2010-02-05 11:54:22

标签: c# appdomain

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

这样做的一种方法是Remoting,我想避免使用它。

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

但是,如果这一切都可以在内存中完成,而不需要在AppDomains之间传递信息的成本,那将是理想的。有人有什么想法吗?

4 个答案:

答案 0 :(得分:27)

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

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

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

您可以找到一个示例应用程序,它作为WMemoryProfiler的一部分。请参阅此链接,了解示例代码的更多detailed explanation and download link

基本代码是

[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);
    }
}

答案 1 :(得分:14)

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

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

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

答案 2 :(得分:4)

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

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

答案 3 :(得分:3)

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