Es ist möglich, Daten zwischen AppDomains ohne die Kosten des Marshalling zu teilen. Aber es ist ein ziemlich hacky Weg. Sie können ein Quelldatenobjekt erstellen, das als Referenz zwischen allen Anwendungsdomänen verwendet wird. Auf diese Weise erhalten Sie alle Daten in einem gemeinsamen Objekt ohne die Kosten des Marshalling. Klingt zu einfach um wahr zu sein?
Die erste Sache ist zu wissen, wie Daten zwischen AppDomains ohne Marshalling teilen. Dazu erhalten Sie die Objektadresse Ihres Datenquellenobjekts über Marshal.UnsafeAddrOfPinnedArrayElement. Dann übergeben Sie diesen IntPtr an alle AppDomains, die daran interessiert sind. In der Ziel-Anwendungsdomäne müssen Sie dieses IntPtr zurück in eine Objektreferenz umwandeln, was mit JIT :: CastAny erledigt werden kann, wenn Sie ein Objekt von einer Methode zurückgeben und dessen Zeiger auf den Stapel schieben.
Viola Sie haben ein Objekt als einfacher Zeiger zwischen AppDomains geteilt und Sie erhalten InvalidCastExceptions. Das Problem ist, dass Sie für alle Ihre AppDomains LoaderOptimization festlegen müssen.MultiDomain, um sicherzustellen, dass die Assembly, die den freigegebenen Datentyp definiert, als neutraler AppDomain-Typ geladen wird, der denselben Methodentabelle-Zeiger zwischen allen AppDomains aufweist.
Sie können eine Beispielanwendung finden, die genau dies als Teil von WMemoryProfiler tut. Siehe diesen Link für eine mehr detailed explanation and download link zum Beispielcode.
Der Grundcode ist
[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);
}
}
Ich habe noch keinen Code geschrieben. Ich arbeite gerade an dem Design. Können Sie mir einen Artikel nennen, der die gemeinsame Nutzung von Daten mit der ersten von Ihnen geposteten Methode erläutert? – ata
Marshalling by Referenz wird die Daten ebenfalls serialisieren, aber in kleinen Stücken. Jeder Methodenaufruf gibt ein bisschen Information zurück, wodurch ein Bit der Daten effektiv serialisiert wird. Dies ist wahrscheinlich eine gute Idee, wenn Sie nur einen kleinen Teil der Daten benötigen. Aber wenn Sie (fast) die gesamten Daten verarbeiten müssen, wird es bei vielen Cross-Domain-Calls Stück für Stück langsamer, verglichen mit der Serialisierung und Übertragung der Daten auf einmal. –
Wenn Sie dieser Straße folgen, vergessen Sie nicht, die InitializeLifetimeService-Methode zu überschreiben; das hat mich vor ein paar Tagen verrückt gemacht ("Objekt '...' wurde getrennt oder existiert nicht auf dem Server.") –