Parallel类、Task类和Parallel LINQ为数据并行性提供了很多帮助。但是,这些类不能直接支持数据流的处理,以及并行转换数据。此时,需要使用Task Parallel Library Data Flow(TPL Data Flow)。
数据流示例的代码使用了如下名称空间:
System
System.IO
System.Threading
System.Threading.Tasks
System.Threading.Tasks.DataFlow
1. 使用动作块
TPL Data Flow的核心是数据块,这些数据块作为提供数据的源或接收数据的目标,或者同时作为源和目标。下面看一个简单的示例,其中用一个数据块来接收一些数据并把数据写入控制台。下面的代码段定义了一个ActionBlock,它接收一个字符串,并把字符串中的信息写入控制台。Main()方法在一个While循环中读取用户输入,然后调用Post()方法把读入的所有字符串写入ActionBlock,Post()方法把一项传递给ActionBlock。ActionBlock异步处理消息,把信息写入控制台:
static void Main(string[] args)
{
//Console.WriteLine("Hello World!");
var processInput = new ActionBlock<string>(s=>
{
Console.WriteLine($"user input: {s}");
});
bool exit = false;
while (!exit)
{
string input = Console.ReadLine();
if (string.Compare(input,"exit",ignoreCase:true) == 0)
{
exit = true;
}
else
{
processInput.Post(input);
}
}
}
运行结果:
Hello
user input: Hello,task id: 1,thread id: 4
World
user input: World,task id: 2,thread id: 5
!
user input: !,task id: 3,thread id: 4
2. 源和目标数据块
以前示例中分配给ActionBlock的方法执行时,ActionBlock会使用一个任务来并行执行。通过检查任何和线程标识符,并把它们写入控制台可以验证这一点。每个块都实现了IDataflowBlock接口,该接口包含了返回一个Task的属性Completion,以及Complete和Fault()方法。调用Complete()方法后,块不再接受任何输入,也不再产生任何输出。调用Fault()方法则把块放入失败状态。
如前所述,块既可以是源,也可以是目标,还可以同时是源和目标。在示例中,ActionBlock是一个目标块,所以实现了ITargetBlock接口。ITargetBlock派生自IDataflowBlock,除了提供IDataflowBlock接口的成员以外,还定义了Off