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 pila.
Viola ha compartido un objeto como un simple puntero entre AppDomains y obtiene InvalidCastExceptions. El problema es que debe establecer para todos sus AppDomains LoaderOptimization.MultiDomain para garantizar que el ensamblado que define el tipo de datos compartidos se cargue como tipo neutral AppDomain, que tiene el mismo puntero 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 un código de muestra más detailed explanation and download link.
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);
}
}
No he escrito el código todavía. Solo trabajando en el diseño. ¿Puede hablarme de algún artículo que explique el uso compartido de datos utilizando el primer enfoque que publicó? – ata
Marshaling por referencia también serializará los datos, pero en pequeños fragmentos. Cada llamada a método devolverá un poco de información serializando efectivamente un poco de los datos. Probablemente sea una buena idea si solo necesita una pequeña porción de los datos. Pero si tiene que procesar (casi) toda la información, obtenerla poco a poco con muchas llamadas de dominio cruzado será increíblemente lenta en comparación con la serialización y la transferencia de datos a la vez. –
Si sigue este camino, no olvide anular el método InitializeLifetimeService; eso me estaba volviendo loco hace unos días ("Objeto '...' ha sido desconectado o no existe en el servidor.") –