5

これが可能かどうかはわかりませんが、可能であれば、おそらく正しく行っていません。多くのコンシューマー (ActionBlocks) にリンクされている 1 つの共有バッファーがあるとします。各コンシューマは、データをバッファにリンクするために使用される述語を満たすデータを消費する必要があります。たとえば、ActionBlock1 は を満たす数値を消費するx => x % 5 == 0必要があり、ActionBlock2 は のみを消費する必要がありますx => x % 5 == 1

これが私が持っているものです:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
    var productionQueue = new BufferBlock<int>();

    for (int i = 0; i < NumProductionLines; i++)
    {
        ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", i + 1, num));

        productionQueue.LinkTo(productionLine, x => x % NumProductionLines == i);
    }

    return productionQueue;
}

そして、私は電話します:

Random rnd = new Random();

ITargetBlock<int> temp = BuildPipeline(5);

while (true)
{
    temp.Post(rnd.Next(255));
}

ただし、これは機能しません。コンソールに出力は表示されません。メソッドを次のように変更した場合BuildPipeline

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
    var productionQueue = new BufferBlock<int>();

    ActionBlock<int> productionLine1 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 1, num));
    ActionBlock<int> productionLine2 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 2, num));
    ActionBlock<int> productionLine3 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 3, num));
    ActionBlock<int> productionLine4 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 4, num));
    ActionBlock<int> productionLine5 = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", 5, num));

    productionQueue.LinkTo(productionLine1, x => x % 5 == 0);
    productionQueue.LinkTo(productionLine2, x => x % 5 == 1);
    productionQueue.LinkTo(productionLine3, x => x % 5 == 2);
    productionQueue.LinkTo(productionLine4, x => x % 5 == 3);
    productionQueue.LinkTo(productionLine5, x => x % 5 == 4);

    return productionQueue;
}

コードは期待どおりに動作します。

アクションブロックの動的な作成とリンクが機能しない理由を誰かが明らかにすることはできますか?

ITargetBlock<int> temp = BuildPipeline(5);PS tempの直後にコードに侵入すると、5 つのターゲットがバッファにリンクされていることが示されます。また、各ターゲットの ID は異なります。

前もって感謝します

編集: svick によって提案された変更を追加しましたが、まだ良くありません:

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
    var productionQueue = new BufferBlock<int>();
    var opt = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 };

    for (int i = 0; i < NumProductionLines; i++)
    {
        ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", i + 1, num));

        int j = i;
        productionQueue.LinkTo(productionLine, x => x % NumProductionLines == j);
    }

    ActionBlock<int> discardedLine = new ActionBlock<int>(num => Console.WriteLine("Discarded: {0}", num));
    productionQueue.LinkTo(discardedLine);

    return productionQueue;
}

現在、2 番目の生産ラインのみがデータを処理します (x % 5 == 1 述語を満たすもの)。データは述語を満たしていません。つまり、9 と 7 で終わる数字が得られます。

編集: 作業コードは次のようになります。

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
    var productionQueue = new BufferBlock<int>();
    var opt = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 };

    for (int i = 0; i < NumProductionLines; i++)
    {
        int j = i;
        ActionBlock<int> productionLine = new ActionBlock<int>(num => Console.WriteLine("Processed by line {0}: {1}", j + 1, num));

        productionQueue.LinkTo(productionLine, x => x % NumProductionLines == j);
    }

    productionQueue.LinkTo(DataflowBlock.NullTarget<int>());

    return productionQueue;
}
4

1 に答える 1

6

問題は、最初のバージョンで、各ターゲット ブロックに同じ述語を使用していることです。つまり、述語は に依存しませんi

しかし、たとえそうであったとしても、i変数は述語間で共有されているため、コードは機能しません。したがって、述語はすべて最後の値を使用します。これを修正するにはi、ローカル変数にコピーし、それを述語で使用します。

コードは次のようになります。

private static ITargetBlock<int> BuildPipeline(int NumProductionLines)
{
    var productionQueue = new BufferBlock<int>();

    for (int i = 0; i < NumProductionLines; i++)
    {
        int iCopy = i;

        ActionBlock<int> productionLine = new ActionBlock<int>(
            num => Console.WriteLine("Processed by line {0}: {1}", iCopy + 1, num));

        productionQueue.LinkTo(
            productionLine, x => x % NumProductionLines == iCopy);
    }

    return productionQueue;
}

コードが少なくとも数値を処理しない理由を尋ねている場合x % 5 == 1、それは、乱数ジェネレーターがその述語に一致しない数値を生成する可能性が高いため、どのActionBlocks もそれを受け入れないためです。そのため、番号はソース ブロックの出力キューに残り、他の番号は通過できなくなります。

実際のコードで同様の状況が発生する可能性があり、述語のいずれにも適合しないすべての数値を破棄したい場合は、ソース ブロックを、何もせず、すべてを受け入れるブロックにリンクできます。あなたの便利なブロック:

productionQueue.LinkTo(DataflowBlock.NullTarget<int>());
于 2012-09-29T09:16:11.790 に答える