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

与前一篇文章演示的流水线思想类似,不同之处就是本文的topic:消费者和生产者有多个,以buffer1为例,起生产者有两个,消费者有两个,现在有三个纬度的并行:
- Action1和Action2并行(消费者和生产者并行)
- 消费者并行(Action2.1和Action2.2并行)
- 生产者并行(Action1.1和Action1.2并行)
二、实现
2.1 代码
class PiplelineDemo
{
PRivate int seed;
public PiplelineDemo()
{
seed = 10;
} public void Action11(BlockingCollection<string> output)
{
for (var i = 0; i < seed; i++)
{
output.Add(i.ToString());//initialize data to buffer1
}
} public void Action12(BlockingCollection<string> output)
{
for (var i = 0; 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 * 2);
var buffer2 = new BlockingCollection<string>(seed * 2);
var buffer3 = new BlockingCollection<string>(seed * 2);
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 代码解释
- Action11和Action12相对比较好理解。初始化数据到buffer1。
- Action2.1和Action2.2相对比较费解,他们同时接受buffer1作为输入,为什么最终的结果Buffer2没有产生重复? 最后由Action21,action22同时产生的buffer3为什么也没有重复?这就是GetConsumingEnumerable这个方法的功劳。这个方法会将buffer的数据分成多份给多个消费者,如果一个value已经被一个消费者获取,那么其他消费者将不会再拿到这个值。这就回答了为什么没有重复这个问题。
- 上面方法同时使用了多任务延续(ContinueWhenAll)对buffer的调用CompleteAdding方法:该方法非常重要,如果没有调用这个方法,程序会进入死锁,因为消费者(consumer)会处于一直的等待状态。
ParallelProgramming-多消费者,多生产者同时运行并行的更多相关文章
- Parallel Programming-多消费者,多生产者同时运行并行
在上一篇文章演示了并行的流水线操作(生产者和消费者并行同时执行),C#是通过BlockingCollection这个线程安全的对象作为Buffer,并且结合Task来实现的.但是上一篇文章有个缺陷,在 ...
- Java多线程消费者、生产者的基本思路
多线程主要考察的就是 线程的同步控制 生产者消费者的思路就是,当 一个线程执行时让另一个线程 挂起就行了 ThreadOne.ThreadTwo同时运行,添加一个变量在一个公共类(下边的Funct ...
- springcloud 实现简单的 消费者和生产者 模式(Restfule 的风格)
一.springcloud 实现简单的 消费者和生产者 模式(Restfule 的风格) 1.实现简单的消费者和生产者 springcloud使用的http协议进行传输数据,也就是说springclo ...
- Java程序设计之消费者和生产者
新建一个Break类,表示食物数量. public class Break { public static final int MAX = 10; //最多一次性煮十个面包 Stack<Inte ...
- java多线程-消费者和生产者模式
/* * 多线程-消费者和生产者模式 * 在实现消费者生产者模式的时候必须要具备两个前提,一是,必须访问的是一个共享资源,二是必须要有线程锁,且锁的是同一个对象 * */ /*资源类中定义了name( ...
- python_并发编程——消费者和生产者模型
消费者和生产者模型 from multiprocessing import Process,Queue import time import random class Producer(Process ...
- 消费者与生产者---LinkedList方式模拟
采用LinkedList数据结构方式来模拟消费者与生产者模型,小Demo import java.util.LinkedList; public class MyQueue { private fin ...
- java并发:初探消费者和生产者模式
消费者和生产者模式 用继承Thread方式,用wait和notifyAll方法实现. 消费者和生产者模式的特点 1. 什么时候生产:仓库没有满的时候,生产者这可以生产,消费者也可以消费,仓库满的时候停 ...
- RabbitMQ消息队列之二:消费者和生产者
在使用RabbitMQ之前,需要了解RabbitMQ的工作原理. RabbitMQ的工作原理 RabbitMQ是消息代理.从本质上说,它接受来自生产者的信息,并将它们传递给消费者.在两者之间,它可以根 ...
随机推荐
- 让button居中显示的的标签
<center> <input type="button" class="buttoncls" style="width:80px& ...
- 在react项目中使用ECharts
这里我们要在自己搭建的react项目中使用ECharts,我们可以在ECharts官网上看到有一种方式是在 webpack 中使用 ECharts,我们需要的就是这种方法. 我们在使用ECharts之 ...
- Android 开发实用方法大全
1.格式化价格,这个经常在计算费用精度的时候用到 /** * 格式化价格 * * @param argStr 传入价格字符串 * @return */ public static String get ...
- Gitlab,这也就O了???
最简单配置也是一句话搞了... rpm -i gitlab-ce--ce..el7.x86_64.rpm vim /etc/gitlab/gitlab.rb gitlab-ctl reconfigur ...
- thinkphp5.0配置nginx重写规则
我的centeros7.3系统,单主机实例: vi /usr/local/nginx/conf/nginx.conf 在如图红框位置加入以下代码(图片是截取的,截取部分上方还有其他的默认配置代码,代码 ...
- 利用return中断function
想实现通过点击button实现文字样式的交替改变,在实现function的中断过程中遇到了一些问题,所幸解决了 <!doctype html> <html lang="en ...
- BIBTeX制作参考文献
一篇关于Latex的参考文献的好文章!基本问题都能解答~ 文章来源:http://www.cnblogs.com/longdouhzt/archive/2012/06/21/2557965.html ...
- AMQ学习笔记 - 08. Spring-JmsTemplate之发送
概述 JmsTemplate提供了3组*3,共计9个发送用的方法. 发送的方法有3组: 基本的发送 转换并发送 转换.后处理再发送 必需的资源 必需的资源有: javax.jms.Connecti ...
- Codeforces 1036E. Covered Points
又一次写起了几何.... 特殊处理在于有可能出现多条线段交于一点的情况,每次考虑时,对每条线段与其他所有线段的交点存在一个set里,对每一个set,每次删除set.size()即可 重点在于判断两条线 ...
- 哈希+Bfs【P2730】 魔板 Magic Squares
没看过题的童鞋请去看一下题-->P2730 魔板 Magic Squares 不了解康托展开的请来这里-->我这里 至于这题为什么可以用康托展开?(瞎说时间到. 因为只有8个数字,且只有1 ...