携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
回顾
这是c#并发编程的第四篇文章,前面我们简单了解了三种并发技术,回顾一下:actor模型,异步和并行三种技术。今天我们在介绍一种并发技术,即:数据流编程技术。
简介
c# 的并行库TPL,我们在上一章并发编程中简单的了解过。在任务并行库TPL中,也提供了数据流并行组件。
在数据流处理中,ISourceBlock 和ITargetBlock接口需要引起重视,根据名字,一个是生产者,一个是消费者。
数据流的处理是将数据分为块数据,并进行网格处理。数据在输入端流入,经过处理网格,然后在输出端流出。
Bufferblock
一个简单的fifo,通过post添加数据,通过receive方法阻塞或者异步的获取数据。也可以通过link向其他的block输出数据。
来一个丐版demo
using System;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
namespace DataFlowDemoS
{
internal class Program
{
//全局buffer
private static BufferBlock<int> m_buffer = new BufferBlock<int>();
/// <summary>
/// 生产者
/// </summary>
private static void Producer1()
{
for(int loop=0;loop<10;loop++)
{
m_buffer.Post(loop);
}
}
/// <summary>
/// 消费者
/// </summary>
private static void Consumer1()
{
while (true)
{
int item = m_buffer.Receive();
Console.WriteLine(item);
}
}
/// <summary>
/// main
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Console.WriteLine("Here We Go!");
var p = Task.Factory.StartNew(Producer1);
var c = Task.Factory.StartNew(Consumer1);
Task.WaitAll(p, c);
}
}
}
效果
ActionBlock
actionblock继承于ITargetBlock,是消费数据block,actionblock会处理fifo中的每一个数据,而且每次只可以处理一个数据,可以通过并行来执行多个数据处理。
actionblock的构造函数中,允许输入一个委托来进行数据处理
demo
using System;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Threading;
namespace DataFlowDemoS
{
internal class Program
{
/// <summary>
/// 消费者
/// </summary>
public static ActionBlock<int> abSync = new ActionBlock<int>((i) =>
{
Thread.Sleep(1000);
Console.WriteLine(i + " ThreadId:" + Thread.CurrentThread.ManagedThreadId + " Execute Time:" + DateTime.Now);
});
/// <summary>
/// 生产者
/// </summary>
public static void TestSync()
{
for (int i = 0; i < 10; i++)
{
abSync.Post(i);
}
Console.WriteLine("生产完毕");
}
/// <summary>
/// main
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Console.WriteLine("Here We Go!");
TestSync();
Console.ReadLine();
}
}
}
效果
数据是异步处理的,生产者生产完毕即退出。消费者在后台处理数据。因为是fifo,也保证了,数据处理的顺序性和准确性。
增加并行处理
actionbloc中提供一些接口,可以让处理数据的线程并行。
我们改造一下之前的消费者,并行3个线程同时处理数据
/// <summary>
/// 消费者
/// </summary>
public static ActionBlock<int> abSync = new ActionBlock<int>((i) =>
{
Thread.Sleep(1000);
Console.WriteLine(i + " ThreadId:" +
Thread.CurrentThread.ManagedThreadId + " Execute Time:" + DateTime.Now);
}, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 3 });
/// <summary>
/// 生产者
/// </summary>
public static void TestSync()
{
for (int i = 0; i < 10; i++)
{
abSync.Post(i);
}
Console.WriteLine("生产完毕");
abSync.Complete();
Console.WriteLine("停止接收数据");
abSync.Completion.Wait();
Console.WriteLine("处理完毕");
}