使用TPL Dataflow进行TransformBlock的实施问题

时间:2015-12-21 23:07:30

标签: c# task-parallel-library reactive-programming tpl-dataflow dataflow

我正在学习TPL数据流。我尝试创建一个示例,其中我发布了来自不同Task的一些值,并期望结果返回到同一Task以进一步处理它。但结果出了问题。以下是我的代码。让我知道我在做什么,以及如何解决它。

static void Main(string[] args)
{

    var transBlock = new TransformBlock<int, int>
       (
           n =>
           {
               Thread.Sleep(1000);

               return (n*2);
           }
       );

    new Task(() => 
    {

       var result = transBlock.Post(2);
       var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 2 is {0}", val));
    }).Start();

    new Task(() =>
    {

        var result = transBlock.Post(3);
        var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 3 is {0}", val));
    }).Start();

    new Task(() =>
    {

        var result = transBlock.Post(4);
        var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 4 is {0}", val));
    }).Start();

    new Task(() =>
    {

        var result = transBlock.Post(5);
        var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 5 is {0}", val));
    }).Start();

    new Task(() =>
    {

        var result = transBlock.Post(6);
        var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 6 is {0}", val));
    }).Start();

    new Task(() =>
    {

        var result = transBlock.Post(7);
        var val = transBlock.Receive();

        Console.WriteLine(string.Format("double for 7 is {0}", val));

    }).Start();

    Console.ReadLine();
}

结果每次都有所不同,但一旦出现这样的结果:

double for 5 is 8
double for 4 is 6
double for 3 is 4
double for 2 is 10
double for 6 is 12
double for 7 is 14

2 个答案:

答案 0 :(得分:3)

这不是TPL数据流的工作方式。

TPL Dataflow是一个actor框架。您创建一个块,您告诉它该做什么,您将项目发布到它中,它一个接一个地(可能同时)执行每个项目的操作,然后输出结果。如果您有多个块,那么您可以将它们链接在一起并形成一个管道。

该块不知道是谁将哪个项目发布到其中。没有理由期望将结果返回到匹配任务。

如果要跟踪输入和输出,可以一起返回输入和输出的元组:

var transBlock = new TransformBlock<int, Tuple<int,int>>(async n =>
{
    await Task.Delay(1000)
    return Tuple.Create(n, n * 2);
});


var tuple = transBlock.Receive();
Console.WriteLine(string.Format("double for {0} is {1}", tuple.Item1, tuple.Item2));

答案 1 :(得分:0)

我不知道TPL Dataflow是否为FIFO,但即使 ,您的代码也会出现竞争条件。

考虑这两个:

new Task(() => 
{

   var result = transBlock.Post(2);
   var val = transBlock.Receive();

    Console.WriteLine(string.Format("double for 2 is {0}", val));
}).Start();

new Task(() =>
{

    var result = transBlock.Post(3);
    var val = transBlock.Receive();

    Console.WriteLine(string.Format("double for 3 is {0}", val));
}).Start();

这些任务可能会也可能不会在不同的线程上执行。但是,如果他们执行,则第二个任务可以发布3,然后将上下文传递给第一个任务,该任务发布2并接收3