Как реализовать истинную функцию конвейера в C #? - PullRequest
5 голосов
/ 13 ноября 2010

Как создать настоящий конвейер функции с помощью C #? У меня есть какая-то идея, как показано ниже, но это не настоящий конвейер

public static IEnumerable<T> ForEachPipeline<T>(this IEnumerable<T> source, params Func<T, T>[] pipeline)
{
 foreach (var element in source) {
  yield return ExecutePipeline(element, pipeline);
 }
}

private static T ExecutePipeline<T>(T element, IEnumerable<Func<T, T>> jobs)
{
 var arg = element;
 T result = default(T);
 foreach (var job in jobs) {
  result = job.Invoke(arg);
  arg = result;
 }
 return result;
}

В приведенном выше коде каждый элемент IEnumerable<T> сможет попасть в конвейер только после того, как предыдущий элемент завершит выполнение всех функций (т.е. выйдет из конвейера), но в соответствии с определением, если element1 завершит выполнение func1 и начать выполнение func2, к этому времени element2 должно начать выполнение func1 и т. д., тем самым поддерживая непрерывный поток данных в конвейере.

Возможен ли такой сценарий для реализации в C #? Если возможно, приведите пример кода.

Ответы [ 3 ]

0 голосов
/ 13 ноября 2010

Я считаю, что один главный архитектурный элемент отсутствует, независимо от того, выполняется задание или нет. Конвейер очень похож на традиционную цепочку ответственности GoF, посмотрите здесь, если у вас нет книги GoF:

http://www.dofactory.com/Patterns/PatternChain.aspx#_self1

Я думаю, что вы должны ограничить свой "T" некоторым интерфейсом, который сообщает конвейеру, если задание было обработано (используйте оператор "where").

Кроме того, взгляните на структуру PLINQ. Я знаю, что это не совсем то, что вы ищете (там есть намерение выполнить несколько заданий параллельно), но это может дать вам несколько хороших идей.

0 голосов
/ 13 ноября 2010

Из комментария: Существует только один контекст выполнения, если не представлены потоки (альтернативный подход с однопоточностью - это просто создание отложенных результатов на каждом шаге).С потоками каждый этап - это просто очередь FIFO, передающая сообщения вокруг «насоса».Потоки (на самом деле, параллелизм) также значительно увеличивают сложность, возможно, смотрите .NET4 «Параллельные» методы.

«Простой» метод - просто настроить N «запускает», используя Parallel.ForEach - если и только если вы можете гарантировать, что вычисления не имеют побочных эффектов.

Редактировать: См. комментарий (ы).

0 голосов
/ 13 ноября 2010

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

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

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