上一篇文章演示了并行的流水线操作(生产者和消费者并行同时执行),C#是通过BlockingCollection这个线程安全的对象作为Buffer,并且结合Task来实现的。但是上一篇文章有个缺陷,在整个流水线上,生产者和消费者是唯一的。本文将演示多个消费者多个生产者同时并行执行。

一、多消费者、多生产者示意图

与前一篇文章演示的流水线思想类似,不同之处就是本文的topic:消费者和生产者有多个,以buffer1为例,起生产者有两个,消费者有两个,现在有三个纬度的并行:

  1. Action1和Action2并行(消费者和生产者并行)
  2. 消费者并行(Action2.1和Action2.2并行)
  3. 生产者并行(Action1.1和Action1.2并行)

二、实现

2.1 代码

 class PiplelineDemo
{
private int seed;
public PiplelineDemo()
{
seed = ;
} public void Action11(BlockingCollection<string> output)
{
for (var i = ; i < seed; i++)
{
output.Add(i.ToString());//initialize data to buffer1
}
} public void Action12(BlockingCollection<string> output)
{
for (var i = ; i < seed; i++)
{
output.Add(i.ToString());//initialize data to buffer1
}
} public void Action21(BlockingCollection<string> input, BlockingCollection<string> output)
{
foreach (var item in input.GetConsumingEnumerable())
{
var itemToInt = int.Parse(item);
output.Add((itemToInt * itemToInt).ToString());// add new data to buffer2
}
} public void Action22(BlockingCollection<string> input, BlockingCollection<string> output)
{
foreach (var item in input.GetConsumingEnumerable())
{
var itemToInt = int.Parse(item);
output.Add((itemToInt * itemToInt).ToString());// add new data to buffer2
}
} public void Action31(BlockingCollection<string> input, BlockingCollection<string> output)
{
foreach (var item in input.GetConsumingEnumerable())
{
output.Add((item));// add new data to buffer3
}
} public void Action32(BlockingCollection<string> input, BlockingCollection<string> output)
{
foreach (var item in input.GetConsumingEnumerable())
{
output.Add((item));// add new data to buffer3
}
}
public void Pipeline()
{
var buffer1 = new BlockingCollection<string>(seed * );
var buffer2 = new BlockingCollection<string>(seed * );
var buffer3 = new BlockingCollection<string>(seed * );
var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
var stage11 = taskFactory.StartNew(() => Action11(buffer1));
var stage12 = taskFactory.StartNew(() => Action12(buffer1));
Task.Factory.ContinueWhenAll(new Task[] { stage11, stage12 }, (tasks) =>
{
buffer1.CompleteAdding();
});
var stage21 = taskFactory.StartNew(() => Action21(buffer1, buffer2));
var stage22 = taskFactory.StartNew(() => Action22(buffer1, buffer2));
Task.Factory.ContinueWhenAll(new Task[] { stage21, stage22 }, (tasks) =>
{
buffer2.CompleteAdding();
});
var stage31 = taskFactory.StartNew(() => Action31(buffer2, buffer3));
var stage32 = taskFactory.StartNew(() => Action32(buffer2, buffer3));
Task.Factory.ContinueWhenAll(new Task[] { stage31, stage32 }, (tasks) =>
{
buffer3.CompleteAdding();
});
Task.WaitAll(stage11, stage12, stage21, stage22, stage31, stage32);
foreach (var item in buffer3.GetConsumingEnumerable())//print data in buffer3
{
Console.WriteLine(item);
}
}
}

2.2 运行结果

2.3 代码解释

  1. Action11和Action12相对比较好理解。初始化数据到buffer1。
  2. Action2.1和Action2.2相对比较费解,他们同时接受buffer1作为输入,为什么最终的结果Buffer2没有产生重复? 最后由Action21,action22同时产生的buffer3为什么也没有重复?这就是GetConsumingEnumerable这个方法的功劳。这个方法会将buffer的数据分成多份给多个消费者,如果一个value已经被一个消费者获取,那么其他消费者将不会再拿到这个值。这就回答了为什么没有重复这个问题。
  3. 上面方法同时使用了多任务延续(ContinueWhenAll)对buffer的调用CompleteAdding方法:该方法非常重要,如果没有调用这个方法,程序会进入死锁,因为消费者(consumer)会处于一直的等待状态。

Parallel Programming-多消费者,多生产者同时运行并行的更多相关文章

  1. ParallelProgramming-多消费者,多生产者同时运行并行

    在上一篇文章演示了并行的流水线操作(生产者和消费者并行同时执行),C#是通过BlockingCollection这个线程安全的对象作为Buffer,并且结合Task来实现的.但是上一篇文章有个缺陷,在 ...

  2. Java多线程消费者、生产者的基本思路

    多线程主要考察的就是 线程的同步控制   生产者消费者的思路就是,当 一个线程执行时让另一个线程 挂起就行了 ThreadOne.ThreadTwo同时运行,添加一个变量在一个公共类(下边的Funct ...

  3. springcloud 实现简单的 消费者和生产者 模式(Restfule 的风格)

    一.springcloud 实现简单的 消费者和生产者 模式(Restfule 的风格) 1.实现简单的消费者和生产者 springcloud使用的http协议进行传输数据,也就是说springclo ...

  4. Java程序设计之消费者和生产者

    新建一个Break类,表示食物数量. public class Break { public static final int MAX = 10; //最多一次性煮十个面包 Stack<Inte ...

  5. Notes of Principles of Parallel Programming - TODO

    0.1 TopicNotes of Lin C., Snyder L.. Principles of Parallel Programming. Beijing: China Machine Pres ...

  6. 4.3 Reduction代码(Heterogeneous Parallel Programming class lab)

    首先添加上Heterogeneous Parallel Programming class 中 lab: Reduction的代码: myReduction.c // MP Reduction // ...

  7. Task Cancellation: Parallel Programming

    http://beyondrelational.com/modules/2/blogs/79/posts/11524/task-cancellation-parallel-programming-ii ...

  8. java多线程-消费者和生产者模式

    /* * 多线程-消费者和生产者模式 * 在实现消费者生产者模式的时候必须要具备两个前提,一是,必须访问的是一个共享资源,二是必须要有线程锁,且锁的是同一个对象 * */ /*资源类中定义了name( ...

  9. Samples for Parallel Programming with the .NET Framework

    The .NET Framework 4 includes significant advancements for developers writing parallel and concurren ...

随机推荐

  1. linux字符集查看与设置

    linux字符集查看与设置 命令:locale -a   查看本地的字符集        locale -m 查看所有支持的字符集   查看当前默认设置   echo $LANG   记录系统默认使用 ...

  2. gIt 常用 操作

    git提交代码流程git status -- 查看当前仓库状态git add  -- 添加到临时仓库git commit -m '注释'  -- 添加到临时仓库git status -- 查看当前仓库 ...

  3. spring jdbcTemplate的CRUD操作

    一.jdbcTemplate准备 1.导入与jdbcTemplate相关的jar包 2.设置数据库信息 3.创建jdbcTemplate对象,设置数据源 二.添加操作 1.代码 2.结果 三.修改操作 ...

  4. php基本语法与函数

    1.标记与注释 <?php 代码 ?> 用/*  */注释一段代码,  用 // 注释一行代码   /**    */文档注释 注意:若php下面只有php代码没有别的代码,那么最好不要加 ...

  5. MOOC 数据结构 01-复杂度3 二分查找

    01-复杂度3 二分查找(20 分) 本题要求实现二分查找算法. 函数接口定义: Position BinarySearch( List L, ElementType X ); 其中List结构定义如 ...

  6. c的详细学习(10)结构体与共用体的学习(二)

    在c语言中,结构体数据类型与共用体数据类型都属于构造类型.共用体与结构体数据类型在定义上十分相似,但它们在存储空间的占用分配上有本质的区别.结构体变量是各种类型数据的集合,各成员占据不同的存储空间,而 ...

  7. hd acm2045

    LELE的RPG难题 析: 假设有N个方格时的涂法是F[N]种.当前边n-1个方格成立时,再加第n种颜色无影响,此时有F[N-1]种涂法,当n-1个方格违法时,即有两个相邻的格子颜色相同,则有n-2个 ...

  8. javascript数字时钟

    <html> <head> <script type="text/javascript"> function startTime() { var ...

  9. <linux是怎么跑的?>傻瓜视角看linux引导启动过程

    每天开机关机,除了“等”之外,你得了解你的操作系统开机的时候真正做了什么? 一. 书上都是这么讲的 CPU自身初始化:硬件初始工作,以PC/IP寄存器跳转到BIOS首地址为结束标志. ->加电自 ...

  10. CDH- 集群时间同步ntp问题解决

    在CDH集群中发现有两台机器获取不到心跳(),导致监控不了机器状态,出现告警 可以使用ntpstat检查与ntp 服务器的时间偏差状态 使用 ntpstat 发现没有同步到ntp时间服务器,运行 nt ...