Możliwe jest udostępnianie danych między AppDomains bez kosztów Marshallingu. Ale jest to dość hackowaty sposób. Można utworzyć obiekt danych źródłowych, który jest współużytkowany przez odniesienie między wszystkimi domenami aplikacji. W ten sposób otrzymasz wszystkie dane w jeden wspólny obiekt bez kosztów Marshallingu. Brzmi zbyt łatwo, aby mogło być prawdziwe?
Pierwszą rzeczą jest wiedzieć, jak udostępniać dane między AppDomains bez Marshalling. W tym celu otrzymujemy adres obiektu twojego obiektu źródła danych przez Marshal.UnsafeAddrOfPinnedArrayElement. Następnie przekazujesz tę IntPtr do wszystkich domen aplikacji, które są tym zainteresowane. W docelowej domenie AppDomain musisz odrzucić tę IntPtr z powrotem do referencji do obiektu, którą można wykonać JIT :: CastAny, która jest wykonywana, jeśli zwrócisz obiekt z metody i popchniesz wskaźnik na stos.
Viola, któremu udostępniłeś obiekt jako zwykły wskaźnik między AppDomains, a otrzymasz InvalidCastExceptions. Problem polega na tym, że musisz ustawić dla wszystkich AppDomains LoaderOptimization.MultiDomain w celu zapewnienia, że zestaw definiujący udostępniony typ danych zostanie załadowany jako typ neutralny AppDomain, który ma ten sam wskaźnik tabeli metod między wszystkimi domenami aplikacji.
Możesz znaleźć przykładową aplikację, która robi to dokładnie jako część WMemoryProfiler. Zobacz ten link, aby uzyskać więcej kodu detailed explanation and download link.
Kod podstawowy jest
[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);
}
}
Nie napisałem jeszcze kodu. Po prostu pracuję nad projektem. Czy możesz powiedzieć mi o jakimś artykule wyjaśniającym udostępnianie danych za pomocą pierwszego opublikowanego przez Ciebie podejścia? – ata
Marshaling przez odniesienie będzie również szeregować dane, ale w małych kawałkach. Każde wywołanie metody zwróci pewną ilość informacji, które sprawnie przetasują część danych. Jest to prawdopodobnie dobry pomysł, jeśli potrzebujesz tylko niewielkiej części danych. Ale jeśli musisz przetworzyć (prawie) całe dane, pobieranie bit po wielu wywołań w wielu domenach będzie niewiarygodnie powolne w porównaniu do serializowania i przesyłania danych naraz. –
Jeśli podążasz tą drogą, nie zapomnij zastąpić metody InitializeLifetimeService; to doprowadzało mnie do szału kilka dni temu ("Obiekt" ... "został odłączony lub nie istnieje na serwerze.") –