Reputation: 7800
the following code blocks on await loader.Completion;
I just can't figure out why?
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace tests {
class Program {
static async Task Main(string[] args) {
Planner pl = new Planner();
Console.WriteLine(await pl.Count());
}
}
public class Planner {
private TransformBlock<int, string[]> loader;
private int _im = 0;
public Planner(int im = 5) {
_im = im;
loader =
new TransformBlock<int, string[]>(
async i => {
Console.WriteLine(i);
await Task.Delay(1000);
return new string[] { i.ToString() };
}
);
}
public async Task<long> Count() {
foreach (int i in Enumerable.Range(1, _im))
loader.Post(i);
//loader.Complete(), same blocking
await loader.Completion;
return -1;
}
}
}
Upvotes: 0
Views: 504
Reputation: 131533
There are two problems here.
1) You didn't tell the block you've finished posting so Completion
will never be signalled.
You need to call loader.Complete()
first :
loader.Complete();
await loader.Completion;
2) The TransformBlock's output has nowhere to go so the block can't complete. A block can't reach the Completed
state until its output buffer is cleared. If you don't care about the output an ActionBlock. Otherwise you'll have to link the block to something else, like a BufferBlock<string[]>
, eg :
var results=new BufferBlock<string[]>();
loader.LinkTo(results);
...
loader.Complete();
await loader.Completion;
Completing one block won't propagate to other linked blocks unless you set the PropagateCompletion
options in the link's options. In this case though there's no reason to propagate completion to the BufferBlock
Upvotes: 8