Как разделить конвейер метода на две или более задач? - PullRequest
0 голосов
/ 25 октября 2019

Это немного сложно объяснить, но я в основном ищу идеи сделать «интересные вещи» с перечислениями, а теперь и задачами. Все начнется с бесконечного перечисления, чтобы бросить 6-гранный кубик:

public static IEnumerable<int> Roll()
{
    while (true) { yield return new Random().Next(1, 7); }
}

Это не слишком увлекательно и служит примером для работы. То, что я хочу, идет глубже ... И включает в себя еще несколько генетических, статических методов. Например:

public static IEnumerable<T> Clock<T>(this IEnumerable<T> source, long totalMs)
{
    var sw = new Stopwatch();
    foreach (var item in source)
    {
        if (!sw.IsRunning) { sw.Restart(); }
        if (sw.ElapsedMilliseconds < totalMs) { yield return item; }
        else { yield break; }
    }
}

Этот метод будет продолжать циклически проходить по перечислению, пока не истечет время. Протестировал и все отлично работает. Теперь я могу использовать это: Dice.Roll().Clock(1000) и мой код будет бросать кубики за одну секунду. И я теперь сделал этот метод:

public static IEnumerable<int> Roll3(this IEnumerable<int> rolls)
{
    int count = 0, total = 0;
    foreach (var die in rolls)
    {
        count += 1;
        total += die;
        if (count == 3)
        {
            yield return total;
            count = 0;
            total = 0;
        }
    }
}

Это может быть написано немного лучше, но это все еще пример. (Используя Take (3) в цикле ...) Но он использует предыдущее бесконечное перечисление следующим образом: Dice.Roll().Clock(1000).Roll3()
Но теперь сложная часть: у меня также есть метод для вычисления общей стоимости всех бросков ипосчитать количество рулонов. Эти методы:

public static IEnumerable<int> Sum(this IEnumerable<int> rolls)
{
    int total = 0;
    foreach (var die in rolls)
    {
        total += die;
        yield return total;
    }
}

public static IEnumerable<int> Count(this IEnumerable<int> rolls)
{
    int count = 0;
    foreach (var die in rolls)
    {
        count += 1;
        yield return count;
    }
}

А теперь настоящая проблема ... Мой код может следовать только одному перечислению, но я делю его на два перечисления. И каждый из них затем разделяется на сумму, сумму и само перечисление. Вышеприведенные методы не могут быть изменены , но я бы хотел увидеть что-то вроде:

Dice.Roll().Clock(1000).Sum().Total().Roll3().Sum().Total();

Но это не получается, очевидно. Именно здесь должны будут использоваться задачи, и я начну выполнять магию многозадачности.
Мне нужен такой метод:

public static IEnumerable<T> SplitPipeLine<T>(this IEnumerable<T> source, **something**)
{
    foreach (var item in source) 
    { 
        yield return item; 
        **Something with task**
    }
}

Или, может быть, какое-то другое решение,Я могу себе представить, что эта задача является своего рода ConcurrentQueue, который будет содержать входящие значения для обработки, которые будут выполняться параллельно с основным перечислением. Так как оба связаны с исходным перечислением, на самом деле не имеет значения, работает ли один быстрее другого. Но я ищу умный способ отделить методы Sum () и Total () от исходного перечисления и от перечисления Roll3 (). Итак, одно перечисление, которое разбито на шесть различных конвейеров ...
Каждый конвейер должен работать внутри своего собственного потока, предпочтительно ... И да, это сложно и, вероятно, может быть решено другими способами. Мне просто любопытно, есть ли какой-нибудь способ решить это таким образом.
Идея состоит в том, что каждый конвейер будет в основном обеспечивать живых результатов на одном перечислении, пока оно перечисляет. Итак, как мне разделить перечисление на несколько перечислений из одного и того же списка? Что-то вроде этого, возможно?

Dice.Roll().Clock(1000).Split(Sum).Split(Total).Split(Roll3, Sum, Total);

Это будет сложно для конвейера Roll3 (), так какоригинальное перечисление Roll () будет в цикле ForEach для основного отображения значений. Остальные - статистика ...

...