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是消息代理.从本质上说,它接受来自生产者的信息,并将它们传递给消费者.在两者之间,它可以根 ...
随机推荐
- 第三方库SDWebImage的原理
关于SDWebImage,其实是不用懂原理的,只是有一些面试官会问,分享给正在找工作的朋友们: 不多说直接上图: 另外..... 我的愿望是....... 世界和平.........
- 1.tornado实现高并发爬虫
from pyquery import PyQuery as pq from tornado import ioloop, gen, httpclient, queues from urllib.pa ...
- 【SQL】视图
一.虚拟视图 由create table定义的表:以物理形式存在,实际存储在数据库中 视图:虚拟的,并不是一个真正存在的表 1.视图定义 CREATE VIEW <视图名> AS < ...
- pytest学习(3)
在pytest 2.0以上的版本里,我们也可以通过python -m pytest ...来调用.这实际上和pytest ...几乎一摸一样. 只是用python的时候,把当面目录也加入到sys.pa ...
- php关于private、protected、public的区别
一句话总结: private 自己的 protected 父亲的 public 大众的
- 《javascript高级程序设计》读书小延伸
这本书已经读了几章了,想着试试能不能做出点东西,就简单的练了把手.觉得对于初学者,自己试着练练,效果还不错的. 挥刀要从轻的开始,起初的原因是和同事谈起曾经的逝水年华(小时候干的坏事)时说起了曾经的一 ...
- 详解Oracle数据货场中三种优化:分区、维度和物化视图
转 xiewmang 新浪博客 本文主要介绍了Oracle数据货场中的三种优化:对分区的优化.维度优化和物化视图的优化,并给出了详细的优化代码,希望对您有所帮助. 我们在做数据库的项目时,对数据货场的 ...
- HDU 1236 排名(结构体+排序)
今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完成的题数排序,没有考虑 每题的分值,所以并不是最后的排名.给定录取分数线,请你写程序找出最后通过分数线的 考生,并将他们的成绩按降序打 ...
- python——入门系列(一)索引与切片
1.索引和切片:python当中数组的索引和其他语言一样,从0~n-1,使用索引的方法也是中括号,但是python中的切片的使用简化了代码 索引:取出数组s中第3个元素:x=s[2] 切片:用极少的代 ...
- HDU 2829 Lawrence
$dp$,斜率优化. 设$dp[i][j]$表示前$i$个数字切了$j$次的最小代价.$dp[i][j]=dp[k][j-1]+p[k+1][i]$.观察状态转移方程,可以发现是一列一列推导出来的.可 ...