代码之家  ›  专栏  ›  技术社区  ›  ata

在AppDomain之间共享数据

  •  16
  • ata  · 技术社区  · 16 年前

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

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

    我唯一想到的另一种方法是将每个AppDomain的数据保存在一个文件中,在特定的时间之后,其中一个AppDomain收集所有数据并进行累积。

    但是,如果这一切都可以在内存中完成,而不需要在AppDomain之间对信息进行序列化。有人有什么想法吗?

    4 回复  |  直到 13 年前
        1
  •  14
  •   Adam Ralph    16 年前

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

    假设引用封送不是一个选项,您将不得不在某个时刻序列化。这是无法避免的。一种方法是像NeilBarnwell建议的那样,使用数据库,另一种方法是使用本地文件,正如您自己建议的那样。

    另一种可能可行或不可行的方法是使用内存映射文件,请参见 .Net Framework 4.0: Using memory mapped files .

        2
  •  24
  •   Alois Kraus    13 年前

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

    第一件事是知道如何在不编组的情况下在AppDomain之间共享数据。为此,您可以通过marshal.unsafeAddrofPinnedArrayElement获取数据源对象的对象地址。然后将此intptr传递给所有对此感兴趣的AppDomain。在目标AppDomain中,需要将此intptr强制转换回对象引用,可以执行jit::castany,如果从方法返回对象并将其指针推到堆栈上,则执行此操作。

    Viola您已经在AppDomain之间共享了一个纯指针对象,并得到了InvalidcastExceptions。问题是,必须为所有AppDomain 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);
        }
    }
    
        3
  •  4
  •   Daniel Brückner    16 年前

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

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

        4
  •  3
  •   Neil Barnwell    16 年前

    我非常感谢您将此内容保存在内存中,但我的第一个建议是将数据写入数据库并从中进行查询。远程处理仍然是一个远程调用,这是使用数据库服务器的大部分“成本”来自于远程调用,您必须构建事务处理以确保不会丢失数据。如果您写入一个SQL Server数据库,您就已经准备好事务支持并在等待您,而且查询速度很快。