2010-01-09 2 views
4

Как правило, это плохая идея передать IEnumerable через границы доменов appdomain?Передача IEnumerable через границы доменов appdomain

Я спрашиваю, потому что с моим нынешним пониманием IEnumerable-реализаций перечислитель не будет использоваться до тех пор, пока коллекция не будет, ну, нумероваться. Когда вы пересекаете границы приложения, в частности, с несколькими процессами, это не приведет к нескольким поездкам через границу, по одному для каждого возвращаемого элемента? Если это так, то возвращение коллекции в полном объеме, когда это возможно, например, в массиве, было бы предпочтительным с точки зрения производительности, не так ли?

ответ

3

Во-первых, это зависит от того, как должен быть перечислит объект: наследуется ли он от MarshalByRef или если он сериализуем. Во втором случае копия передается другому appdomain, который затем напоминает подход массива. С другой стороны, если он наследует от MarshalByRef, это в значительной степени зависит от того, как перечислитель обращается к экземпляру владельца.

Так что, в общем, я бы сказал, что вы должны передавать только IEnumerable с помощью приложений, если вы знаете, чего ожидать. В противном случае вы можете получить неожиданные результаты или плохую производительность.

+0

Я должен был уточнить, что принимаю MBR. Учитывая, что этот ответ и другие ответы, я думаю, что я буду избегать возвращаемых значений IEnumerable, если в конкретном случае нет хорошего аргумента. – redman

1

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

0

Да. небезопасно даже передавать его через потоки. вам лучше преобразовать его в массив, чтобы пройти.

+0

Re "safe" - если потоки (или 'AppDomain' в этом случае) хорошо себя ведут, это не проблема; но я согласен с массивами ... –

2

Фактически, если MarshalByRefObject, это поездки за пункт (плюс один); один на MoveNext(), а один на Current (за каждые MoveNext(), который возвращает true). Плюс a GetEnumerator() звонок, и, вероятно, Dispose(). Итак, для MarshalByRefObject нет: не делайте этого; используйте массив.

Однако, если это неMarshalByRefObject это более интересно. Например, службы данных ADO.NET предоставляют данные по API LINQ (IQueryable<T> : IEnumerable<T>), но это работает, создавая конкретный запрос, когда это необходимо, совершая однократную поездку и повторяя обратно клиент.

Конечно, вы, вероятно, не следуешь использовать Remoting над любым реальным расстоянием (предпочитает WCF и т.д.), так что, может быть, первый сценарий не является огромной проблемы - вы не будете иметь много латентности , Кроме того, у вас будут одинаковые проблемы с задержкой для объектов (если MarshalByRefObject) или сериализации (если нет).

Лично на очень мало раз я использую Remoting (как правило, только чтобы Dll разгрузку), у меня есть MarshalByRefObject представлять какую-то службу, и сериализуемые объектов сущностей. Возможно, для меня это предсказуемо, я использую protobuf-net для минимизации сериализации.

+0

Я тоже обдумывал это, и пришли те же выводы.Я пытался найти баланс между большим сериализованным объектом за один проход, который будет отфильтрован в другом домене, а также передаст запрос linq в домене, который будет выполнен, а затем будет сериализован подмножеством. Возникает вопрос, можете ли вы передать запрос linq через домен без негативных эффектов (например, запретить одному домену загружать другие типы?). Любые мысли по этому поводу? – JoeBrockhaus

+0

@Joe интересная мысль, возможно: именованный файл с отображением памяти. Открыли ли они оба приложения-домены с отдельными хостами процесса (перечисляемые части локально для каждого домена приложения). Пусть ОС беспокоится о базовых данных. –

+0

А, я вижу. Я должен подумать об этом. (Я просто думал о расширяемости нашей текущей плагиновой структуры.) – JoeBrockhaus