《Java高并发程序设计》学习 --5.6 并行流水线
2017-03-25 09:15
176 查看
并发算法虽然可以充分发挥多核CPU的性能,但并非所有的计算都可以改造成并发形式。执行过程中有数据相关性的运算都是无法完美并行化的。
假如现在有两个数,B和C。如果要计算(B+C)*B/2,那么这个运算过程就是无法并行的。原因是,如果B+C没有执行完成,则永远算不出(B+C)*B,这就是数据相关性。
遇到这种情况,可以借鉴日常生产中的流水线思想。
类似的思想可以借鉴到程序开发中。即使(B+C)*B/2无法并行,但是如果需要计算一大堆B和C,可以将它流水话。首先将计算过程拆分为三个步骤:
P1:A=B+C
P2:D=AxB
P3:D=D/2
上述步骤中P1、P2和P3均在单独的线程中计算,并且每个线程只负责自己的工作。此时,P3的计算结果就是最终需要的答案。
P1接收B和C的值,并求和,将结果输入P2。P2求乘积后输入给P3。P3将D除以2得到最终值。一旦这条流水线建立,只需要一个计算步骤就可以得到(B+C)*B/2的结果。
为了实现这个功能,需要定义一个在线程间携带结果进行信息交换的载体:
P1计算的是加法:
上述代码中,P1取得封装了两个操作数的Msg,并进行求和,将结果传递给乘法线程P2。当没有数据需要处理时,P1进行等待。
P2计算乘法:
和P1非常类似,P2计算相乘结果后,将中间结果传递给除法线程P3。
P3计算除法:
P3将结果除以2后输出最终结果。
最后是提交任务的主线程,这里,提交100万个请求,让线程组进行计算:
上述代码中,将数据提交给P1加法线程,开启流水线的计算。在多核或者分布式场景中,这种设计思路可以有效地将有依赖关系的操作分配在不同的线程中进行计算,尽可能利用多核优势。
注:本篇博客内容摘自《Java高并发程序设计》
假如现在有两个数,B和C。如果要计算(B+C)*B/2,那么这个运算过程就是无法并行的。原因是,如果B+C没有执行完成,则永远算不出(B+C)*B,这就是数据相关性。
遇到这种情况,可以借鉴日常生产中的流水线思想。
类似的思想可以借鉴到程序开发中。即使(B+C)*B/2无法并行,但是如果需要计算一大堆B和C,可以将它流水话。首先将计算过程拆分为三个步骤:
P1:A=B+C
P2:D=AxB
P3:D=D/2
上述步骤中P1、P2和P3均在单独的线程中计算,并且每个线程只负责自己的工作。此时,P3的计算结果就是最终需要的答案。
P1接收B和C的值,并求和,将结果输入P2。P2求乘积后输入给P3。P3将D除以2得到最终值。一旦这条流水线建立,只需要一个计算步骤就可以得到(B+C)*B/2的结果。
为了实现这个功能,需要定义一个在线程间携带结果进行信息交换的载体:
public class Msg { public double i; public double j; public String orgStr = null; }
P1计算的是加法:
public class Plus implements Runnable { public static BlockingQueue<Msg> bq = new LinkedBlockingQueue<Msg>(); @Override public void run() { while(true) { try { Msg msg = bq.take(); msg.j = msg.i + msg.j; Multiply.bq.add(msg); } catch (InterruptedException e) { } } } }
上述代码中,P1取得封装了两个操作数的Msg,并进行求和,将结果传递给乘法线程P2。当没有数据需要处理时,P1进行等待。
P2计算乘法:
public class Multiply implements Runnable { public static BlockingQueue<Msg> bq = new LinkedBlockingQueue<Msg>(); @Override public void run() { while(true) { try { Msg msg = bq.take(); msg.i = msg.i * msg.j; Div.bq.add(msg); } catch (InterruptedException e) { } } } }
和P1非常类似,P2计算相乘结果后,将中间结果传递给除法线程P3。
P3计算除法:
public class Div implements Runnable { public static BlockingQueue<Msg> bq = new LinkedBlockingQueue<Msg>(); @Override public void run() { while(true) { try { Msg msg = bq.take(); msg.i = msg.i / 2; System.out.println(msg.orgStr + "=" + msg.i); } catch (InterruptedException e) { } } } }
P3将结果除以2后输出最终结果。
最后是提交任务的主线程,这里,提交100万个请求,让线程组进行计算:
public class PStreamMain { public static void main(String[] args) { new Thread(new Plus()).start(); new Thread(new Multiply()).start(); new Thread(new Div()).start(); long s1 = System.currentTimeMillis(); for(int i=1; i<=1000; i++) { for(int j=1; j<=1000; j++) { Msg msg = new Msg(); msg.i = i; msg.j = j; msg.orgStr = "((" + i + "+" + j + ")*" + i + ")/2"; Plus.bq.add(msg); } } } }
上述代码中,将数据提交给P1加法线程,开启流水线的计算。在多核或者分布式场景中,这种设计思路可以有效地将有依赖关系的操作分配在不同的线程中进行计算,尽可能利用多核优势。
注:本篇博客内容摘自《Java高并发程序设计》
相关文章推荐
- 《Java高并发程序设计》学习 --5.3 并行模式之生产者-消费者模式
- 《Java高并发程序设计》学习 --5.7 并行搜索
- 《Java高并发程序设计》学习 --1.3有关并行的两个重要定律
- 《Java高并发程序设计》学习 --5.9 并行模式之并行算法:矩阵乘法
- 《Java高并发程序设计》学习 --5.5 并行模式之 Future模式
- 《Java高并发程序设计》学习 --5.2 并行模式之不变模式
- 学习散记9之---并行查询处理
- 并行知识学习
- MSP430学习笔记8-ST7920 12864液晶显示并行接口
- ORACLE并行操作学习
- centos5.6入门学习002之centos5.6安装
- 微软企业库4.1学习笔记(三)企业库迁移和并行使用,以及企业库的扩展
- MPI 学习 -- 高性能计算之并行编程技术 --- MPI并行程序设计 都志辉编著
- MSP430学习笔记8-ST7920 12864液晶显示并行接口
- java学习 java中接口运用演示并行开发.....暑假第五天
- 并行运算学习(1)
- .NET 4.0并行计算学习笔记
- 分布式、并行计算语言Erlang 学习笔记(第三部分)
- 流水线学习笔记(二)
- 微软企业库4.1学习笔记(三)企业库迁移和并行使用,以及企业库的扩展