Reputation: 3471
I am learning TPL dataflow. I tried creating a sample where I am posting some values from different Task
s and expecting the result back in the same Task
to process it further. But the result is coming wrong. Following is my code. Let me know what wrong I am doing and how to resolve it.
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();
}
Result varies each time but once it came like this:
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
Upvotes: 0
Views: 218
Reputation: 116558
That's not how TPL Dataflow works.
TPL Dataflow is an actor framework. You create a block, you tell it what to do, you post items into it and it executes the operation for each item one after the other (possibly concurrently) and then outputs the results. If you have multiple blocks then you can chain them one together and form a pipeline.
The block doesn't know who posted which item into it. There's no reason to expect the result to be returned to the matching task.
If you want to keep track of the input and output you can return a tuple of the input and output together:
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));
Upvotes: 4
Reputation: 27367
I do not know if TPL Dataflow
is FIFO, but even if it is, your code has a race condition.
Consider just these two:
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();
These tasks may or may not execute on separate threads. However, if they do, it's possible for the second task to post 3
, and then pass the context to the first task, which posts 2
and receives 3
.
Upvotes: 0