C# 为什么此代码挂起“等待TransformBlock.Completion”`

C# 为什么此代码挂起“等待TransformBlock.Completion”`,c#,.net-core,task-parallel-library,tpl-dataflow,C#,.net Core,Task Parallel Library,Tpl Dataflow,上的以下代码块等待加载程序完成 我就是不明白为什么 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 Planne

上的以下代码块等待加载程序完成

我就是不明白为什么

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;
        }
    }
}
使用系统;
使用System.Linq;
使用System.Threading.Tasks;
使用System.Threading.Tasks.Dataflow;
命名空间测试{
班级计划{
静态异步任务主(字符串[]args){
规划师pl=新规划师();
Console.WriteLine(wait pl.Count());
}
}
公共课程规划师{
专用块装载机;
私有int _im=0;
公共规划师(int im=5){
_im=im;
装载机=
新转换块(
异步i=>{
控制台写入线(i);
等待任务。延迟(1000);
返回新字符串[]{i.ToString()};
}
);
}
公共异步任务计数(){
foreach(可枚举范围(1,_-im)中的int i)
装载机.邮政(i);;
//loader.Complete(),相同的阻塞
等待装载机完成;
返回-1;
}
}
}

这里有两个问题

1)你没有告诉区块你已经完成了发布,因此
完成
将永远不会收到信号

您需要先调用
loader.Complete()

loader.Complete();
await loader.Completion;
2)TransformBlock的输出无处可去,因此该块无法完成。在清除其输出缓冲区之前,块无法达到
已完成
状态。如果您不关心输出,请创建ActionBlock。否则,您必须将该块链接到其他对象,如
缓冲块
,例如:

var results=new BufferBlock<string[]>();

loader.LinkTo(results);

...
loader.Complete();
await loader.Completion;
var results=new BufferBlock();
loader.LinkTo(结果);
...
loader.Complete();
等待装载机完成;
完成一个块不会传播到其他链接块,除非在链接的选项中设置
PropagateCompletion
选项。在这种情况下,虽然没有理由将完成传播到BufferBlock