Compartir datos entre AppDomains

Tengo un proceso que puede tener múltiples AppDomains. Cada AppDomain recoge algunas estadísticas. Después de un tiempo específico, quiero acumular estas estadísticas y guardarlas en un archivo.

Una forma de hacerlo es Remoting, que quiero evitar.

La única otra técnica que tengo en mente es guardar los datos de cada dominio de aplicación en un archivo, y después de un tiempo específico, uno de los dominios de aplicación recoge todos los datos y los acumula.

Pero sería ideal si todo esto se pudiera hacer en la memoria, sin el costo de serializar la información para pasar entre los AppDomains. ¿Alguien tiene alguna idea?

La única forma de evitar la serialización es representar sus datos utilizando objetos que se derivan de MarshalByRefObject, pero en ese caso todavía tendrá que pagar el costo de coordinar los límites de AppDomain. Esto también puede implicar la refacturación / reescritura de gran parte de su código.

Suponiendo que la clasificación por referencia no es una opción, tendrá que serializar en algún momento. Simplemente no se puede evitar. Una forma de hacer esto es como sugiere Neil Barnwell, con una base de datos, otra sería con un archivo local como usted mismo sugiere.

Otra forma que puede o no ser factible dependiendo de su calendario de entrega y / o adopción de .NET 4.0, sería utilizar un archivo mapeado de memoria, vea .NET Framework 4.0: Uso de archivos mapeados en memoria .

Es posible compartir datos entre AppDomains sin los costos de Marshalling. Pero es una forma bastante hacky. Puede crear un objeto de datos fuente que se comparte por referencia entre todos los AppDomains. De esta forma, obtiene todos los datos en un objeto compartido sin los costos de Marshalling. Suena demasiado fácil para ser verdad?

Lo primero es saber cómo compartir datos entre AppDomains sin Marshalling. Para esto obtienes la dirección del objeto de tu fuente de datos a través de Marshal.UnsafeAddrOfPinnedArrayElement. Luego pasas este IntPtr a todos los AppDomains que estén interesados ​​en esto. En el AppDomain de destino, necesita volver a convertir este IntPtr a una referencia de objeto que se puede hacer JIT :: CastAny, que se realiza si devuelve un objeto de un método y lo inserta en la stack.

Viola ha compartido un objeto como un simple indicador entre AppDomains y obtiene InvalidCastExceptions. El problema es que debe establecer para todos sus AppDomains LoaderOptimization.MultiDomain para asegurarse de que el ensamblado que define el tipo de datos compartidos se cargue como tipo neutral de AppDomain, que tiene el mismo puntero de Tabla de métodos entre todos los AppDomains.

Puede encontrar una aplicación de ejemplo que hace exactamente esto como parte de WMemoryProfiler. Consulte este enlace para obtener una explicación más detallada y un enlace de descarga para el código de muestra.

El código básico es

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

Tiendo a decir que solo uso la comunicación remota. Escribir los datos en un archivo también requiere serialización. La serialización parece ser casi inevitable, sea cual sea la tecnología que utilice. Tienes que transferir datos de un dominio de aplicación a otro usando algún canal y tendrás que serializar los datos para poder acceder a través del canal.

La única forma de evitar la serialización parece ser utilizar la memoria compartida para que ambos dominios de aplicación puedan acceder a los datos sin tener que pasar por un canal. Incluso la clonación profunda de los datos de la memoria de un dominio de aplicación en la memoria del otro es en esencia nada más que una serialización binaria (donde el resultado no se almacena necesariamente en ubicaciones de memoria consecutivas).

Aprecio que quieras mantener esto en la memoria, pero mi primera sugerencia sería escribir los datos en una base de datos y consultar desde allí. Remoting es aún una llamada remota, que es de donde proviene gran parte del “costo” de usar un servidor de base de datos, y usted tendría que desarrollar el manejo de transacciones para asegurarse de no perder datos. Si escribe en una base de datos de SQL Server, tiene el soporte de transacciones listo y esperando por usted, y es rápido y rápido para las consultas.