Обмен данными между доменами приложений - PullRequest
18 голосов
/ 05 февраля 2010

У меня есть процесс, который может иметь несколько доменов приложений. Каждый AppDomain собирает некоторую статистику. По истечении указанного времени я хочу накапливать эти статистические данные и сохранять их в файл.

Один из способов сделать это - удаленное взаимодействие, которого я хочу избежать.

Единственный другой метод, который я имею в виду, - это сохранение данных каждого домена приложений в файл, и по истечении определенного времени один из доменов приложений собирает все данные и накапливает их.

Но было бы идеально, если бы все это можно было делать в памяти без затрат на сериализацию информации, передаваемой между доменами приложений. У кого-нибудь есть идеи?

Ответы [ 4 ]

27 голосов
/ 26 июля 2012

Существует возможность обмена данными между доменами приложений без затрат на Marshalling. Но это довольно хакерский способ. Вы можете создать исходный объект данных, который по ссылке будет использоваться всеми доменами приложений. Таким образом, вы получаете все данные в один общий объект без затрат на Marshalling. Звучит слишком легко, чтобы быть правдой?

Первое, что нужно знать, это как делиться данными между доменами приложений без Marshalling. Для этого вы получите адрес объекта вашего источника данных через Marshal.UnsafeAddrOfPinnedArrayElement. Затем вы передаете этот IntPtr всем доменам приложений, которые заинтересованы в этом. В целевом AppDomain вам необходимо преобразовать этот IntPtr обратно в ссылку на объект, что можно сделать JIT :: CastAny, что делается, если вы возвращаете объект из метода и помещаете его указатель в стек.

Виола, вы разделили объект как простой указатель между доменами приложений и получили InvalidCastExceptions. Проблема заключается в том, что вы должны установить для всех ваших доменов приложений LoaderOptimization.MultiDomain, чтобы гарантировать, что сборка, определяющая общий тип данных, загружается как нейтральный тип AppDomain, имеющий одинаковый указатель таблицы методов между всеми доменами приложений.

Вы можете найти пример приложения, которое делает именно это как часть WMemoryProfiler. См. Эту ссылку для получения более подробного объяснения и ссылки для загрузки с примером кода.

Основной код

[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);
    }
}
14 голосов
/ 05 февраля 2010

Единственный способ избежать сериализации - это представить ваши данные, используя объекты, которые являются производными от MarshalByRefObject, но в этом случае вам все равно придется оплачивать маршалинг через границы AppDomain.Это может также включать рефакторинг / переписывание большей части вашего кода.

Предполагая, что сортировка по ссылке не является вариантом, вам придется сериализоваться в какой-то момент.Этого просто невозможно избежать.Один из способов сделать это, как предлагает Нейл Барнвелл, с базой данных, другой - с локальным файлом, как вы предлагаете сами.

Другой способ, который может или не может быть осуществим в зависимости от сроков доставки и / или.Принятие NET 4.0, будет использовать файл сопоставления памяти, см. .Net Framework 4.0: Использование файлов сопоставления памяти .

4 голосов
/ 05 февраля 2010

Я имею в виду, просто используйте удаленное взаимодействие. Запись данных в файл также требует сериализации. Сериализация кажется почти неизбежной, какую бы технологию вы ни использовали. Вы должны передавать данные из одного домена приложения в другой, используя какой-либо канал, и вам придется сериализовать данные, чтобы получить их через канал.

Единственный способ избежать сериализации, по-видимому, заключается в использовании разделяемой памяти, чтобы оба домена приложений могли обращаться к данным, даже не проходя через канал. Даже глубокое клонирование данных из памяти одного домена приложения в память другого по своей сути представляет собой не что иное, как двоичную сериализацию (где результат не обязательно сохраняется в последовательных ячейках памяти).

3 голосов
/ 05 февраля 2010

Я действительно ценю, что вы хотите сохранить это в памяти, но мое первое предложение - записать данные в базу данных и запросить оттуда. Удаленное взаимодействие по-прежнему является удаленным вызовом, из которого исходит большая часть «затрат» на использование сервера базы данных, и вам придется встроить обработку транзакций, чтобы не потерять данные. Если вы пишете в базу данных SQL Server, у вас есть готовая и ожидающая поддержка транзакций, и она быстро-быстро-быстро для запросов.

...