精华内容
下载资源
问答
  • Oracle并行模式(Parallel)

    万次阅读 2017-09-06 18:00:39
    用途 强行启用并行度来执行当前SQL。这个在Oracle 9i之后的版本可以使用,之前的版本现在没有环境进行测试。也就是说,加上这个说明,可以强行启用Oracle的多线程处理功能。举例的话,就像电脑装了多核的CPU,但...

    1. 实例

    (1)insert 加速

    insert/*+ append parallel nologging */ into dcustcomposmsg 
    select /*+ parallel(e,18)*/ * from dcustcomposmsg_new e; 
    commit;

    (2)select create加速
    CREATE TABLE TEMP_DCUST_GRADE  NOLOGGING PARALLEL 10 AS
                       SELECT /*+PARALLEL(D,10)*/ *
                        FROM DCUST_BASIC_INFO_D PARTITION (P_'||V_TOLL_NO||') D 
                       WHERE EXISTS(SELECT ''A'' FROM DCUSTHIGH PARTITION (P_'||V_REGION_CODE||') A
                       WHERE D.ID_NO = A.ID_NO )

    2. 用途

    强行启用并行度来执行当前SQL。这个在Oracle 9i之后的版本可以使用,之前的版本现在没有环境进行测试。也就是说,加上这个说明,可以强行启用Oracle的多线程处理功能。举例的话,就像电脑装了多核的CPU,但大多情况下都不会完全多核同时启用(2核以上的比较明显),使用parallel说明,就会多核同时工作,来提高效率。

    但本身启动这个功能,也是要消耗资源与性能的。所有,一般都会在返回记录数大于100万时使用,效果也会比较明显。

    3. 语法
    /*+parallel(table_short_name,cash_number)*/

    这个可以加到insert、delete、update、select的后面来使用(和rule的用法差不多,有机会再分享rule的用法)

    开启parallel功能的语句是:

    alter session enable parallel dml;

    这个语句是DML语句哦,如果在程序中用,用execute的方法打开。

    4. 实例说明

    用ERP中的transaction来说明下吧。这个table记录了所有的transaction,而且每天数据量也算相对比较大的(根据企业自身业务量而定)。假设我们现在要查看对比去年一年当中每月的进、销情况,所以,一般都会写成:

    select to_char(transaction_date,'yyyymm') txn_month,

           sum(

            decode(

                sign(transaction_quantity),1,transaction_quantity,0
                  )

              ) in_qty,

           sum(

            decode(

                sign(transaction_quantity),-1,transaction_quantity,0
                  )

              ) out_qty

      from mtl_material_transactions mmt

    where transaction_date >= add_months(

                                to_date(    

                                    to_char(sysdate,'yyyy')||'0101','yyyymmdd'),

                                    -12)

       and transaction_date <= add_months(

                                to_date(

                                    to_char(sysdate,'yyyy')||'1231','yyyymmdd'),

                                    -12)

    group by to_char(transaction_date,'yyyymm') 

    这个SQL执行起来,如果transaction_date上面有加index的话,效率还算过的去;但如果没有加index的话,估计就会半个小时内都执行不出来。这是就可以在select 后面加上parallel说明。例如:
    select /*+parallel(mmt,10)*/
           to_char(transaction_date,'yyyymm') txn_month,

    ...



    这样的话,会大大提高执行效率。如果要将检索出来的结果insert到另一个表tmp_count_tab的话,也可以写成:
    insert /*+parallel(t,10)*/
      into tmp_count_tab

    (

        txn_month,

        in_qty,

        out_qty

    )

    select /*+parallel(mmt,10)*/
           to_char(transaction_date,'yyyymm') txn_month,

    ...



    插入的机制和检索机制差不多,所以,在insert后面加parallel也会加速的。关于insert机制,这里暂不说了。
    Parallel后面的数字,越大,执行效率越高。不过,貌似跟server的配置还有oracle的配置有关,增大到一定值,效果就不明显了。所以,一般用8,10,12,16的比较常见。我试过用30,发现和16的效果一样。不过,数值越大,占用的资源也会相对增大的。如果是在一些package、function or procedure中写的话,还是不要写那么大,免得占用太多资源被DBA开K。
      

    5. Parallel也可以用于多表

    多表的话,就是在第一后面,加入其他的就可以了。具体写法如下:

    /*+parallel(t,10) (b,10)*/

    6. 小结

    关于执行效率,建议还是多按照index的方法来提高效果。Oracle有自带的explan road的方法,在执行之前,先看下执行计划路线,对写好的SQL tuned之后再执行。实在没办法了,再用parallel方法。Parallel比较邪恶,对开发者而言,不是好东西,会养成不好习惯,导致很多bad SQL不会暴漏,SQL Tuning的能力得不到提升。我有见过某些人create table后,从不create index或primary key,认为写SQL时加parallel就可以了。

    展开全文
  • 上篇文章提起关于HBase插入性能优化设计到的五个参数,从参数配置的角度给大家提供了一个性能测试环境的实验代码。...本文给出了基于多线程并发模式的,测试代码案例和实测结果,希望能给大家一些启示。

    一、引言:

      上篇文章提起关于HBase插入性能优化设计到的五个参数,从参数配置的角度给大家提供了一个性能测试环境的实验代码。根据网友的反馈,基于单线程的模式实现的数据插入毕竟有限。通过个人实测,在我的虚拟机环境下,单线程插入数据的值约为4w/s。集群指标是:CPU双核1.83,虚拟机512M内存,集群部署单点模式。本文给出了基于多线程并发模式的,测试代码案例和实测结果,希望能给大家一些启示:

    二、源程序:

    复制代码
      1 import org.apache.hadoop.conf.Configuration;
      2 import org.apache.hadoop.hbase.HBaseConfiguration;
      3 import java.io.BufferedReader;
      4 import java.io.File;
      5 import java.io.FileNotFoundException;
      6 import java.io.FileReader;
      7 import java.io.IOException;
      8 import java.util.ArrayList;
      9 import java.util.List;
     10 import java.util.Random;
     11 
     12 import org.apache.hadoop.conf.Configuration;
     13 import org.apache.hadoop.hbase.HBaseConfiguration;
     14 import org.apache.hadoop.hbase.client.HBaseAdmin;
     15 import org.apache.hadoop.hbase.client.HTable;
     16 import org.apache.hadoop.hbase.client.HTableInterface;
     17 import org.apache.hadoop.hbase.client.HTablePool;
     18 import org.apache.hadoop.hbase.client.Put;
     19 
     20 public class HBaseImportEx {
     21     static Configuration hbaseConfig = null;
     22     public static HTablePool pool = null;
     23     public static String tableName = "T_TEST_1";
     24     static{
     25          //conf = HBaseConfiguration.create();
     26          Configuration HBASE_CONFIG = new Configuration();
     27          HBASE_CONFIG.set("hbase.master", "192.168.230.133:60000");
     28          HBASE_CONFIG.set("hbase.zookeeper.quorum", "192.168.230.133");
     29          HBASE_CONFIG.set("hbase.zookeeper.property.clientPort", "2181");
     30          hbaseConfig = HBaseConfiguration.create(HBASE_CONFIG);
     31          
     32          pool = new HTablePool(hbaseConfig, 1000); 
     33     }
     34     /*
     35      * Insert Test single thread
     36      * */
     37     public static void SingleThreadInsert()throws IOException
     38     {
     39         System.out.println("---------开始SingleThreadInsert测试----------");
     40         long start = System.currentTimeMillis();
     41         //HTableInterface table = null;
     42         HTable table = null;
     43         table = (HTable)pool.getTable(tableName);
     44         table.setAutoFlush(false);
     45         table.setWriteBufferSize(24*1024*1024);
     46         //构造测试数据
     47         List<Put> list = new ArrayList<Put>();
     48         int count = 10000;
     49         byte[] buffer = new byte[350];
     50         Random rand = new Random();
     51         for(int i=0;i<count;i++)
     52         {
     53             Put put = new Put(String.format("row %d",i).getBytes());
     54             rand.nextBytes(buffer);
     55             put.add("f1".getBytes(), null, buffer);
     56             //wal=false
     57             put.setWriteToWAL(false);
     58             list.add(put);    
     59             if(i%10000 == 0)
     60             {
     61                 table.put(list);
     62                 list.clear();    
     63                 table.flushCommits();
     64             }            
     65         }
     66         long stop = System.currentTimeMillis();
     67         //System.out.println("WAL="+wal+",autoFlush="+autoFlush+",buffer="+writeBuffer+",count="+count);
     68           
     69         System.out.println("插入数据:"+count+"共耗时:"+ (stop - start)*1.0/1000+"s");
     70         
     71         System.out.println("---------结束SingleThreadInsert测试----------");
     72     }
     73     /*
     74      * 多线程环境下线程插入函数 
     75      * 
     76      * */
     77     public static void InsertProcess()throws IOException
     78     {
     79         long start = System.currentTimeMillis();
     80         //HTableInterface table = null;
     81         HTable table = null;
     82         table = (HTable)pool.getTable(tableName);
     83         table.setAutoFlush(false);
     84         table.setWriteBufferSize(24*1024*1024);
     85         //构造测试数据
     86         List<Put> list = new ArrayList<Put>();
     87         int count = 10000;
     88         byte[] buffer = new byte[256];
     89         Random rand = new Random();
     90         for(int i=0;i<count;i++)
     91         {
     92             Put put = new Put(String.format("row %d",i).getBytes());
     93             rand.nextBytes(buffer);
     94             put.add("f1".getBytes(), null, buffer);
     95             //wal=false
     96             put.setWriteToWAL(false);
     97             list.add(put);    
     98             if(i%10000 == 0)
     99             {
    100                 table.put(list);
    101                 list.clear();    
    102                 table.flushCommits();
    103             }            
    104         }
    105         long stop = System.currentTimeMillis();
    106         //System.out.println("WAL="+wal+",autoFlush="+autoFlush+",buffer="+writeBuffer+",count="+count);
    107           
    108         System.out.println("线程:"+Thread.currentThread().getId()+"插入数据:"+count+"共耗时:"+ (stop - start)*1.0/1000+"s");
    109     }
    110     
    111     
    112     /*
    113      * Mutil thread insert test
    114      * */
    115     public static void MultThreadInsert() throws InterruptedException
    116     {
    117         System.out.println("---------开始MultThreadInsert测试----------");
    118         long start = System.currentTimeMillis();
    119         int threadNumber = 10;
    120         Thread[] threads=new Thread[threadNumber];
    121         for(int i=0;i<threads.length;i++)
    122         {
    123             threads[i]= new ImportThread();
    124             threads[i].start();            
    125         }
    126         for(int j=0;j< threads.length;j++)
    127         {
    128              (threads[j]).join();
    129         }
    130         long stop = System.currentTimeMillis();
    131           
    132         System.out.println("MultThreadInsert:"+threadNumber*10000+"共耗时:"+ (stop - start)*1.0/1000+"s");        
    133         System.out.println("---------结束MultThreadInsert测试----------");
    134     }    
    135 
    136     /**
    137      * @param args
    138      */
    139     public static void main(String[] args)  throws Exception{
    140         // TODO Auto-generated method stub
    141         //SingleThreadInsert();        
    142         MultThreadInsert();
    143         
    144         
    145     }
    146     
    147     public static class ImportThread extends Thread{
    148         public void HandleThread()
    149         {                        
    150             //this.TableName = "T_TEST_1";
    151         
    152             
    153         }
    154         //
    155         public void run(){
    156             try{
    157                 InsertProcess();            
    158             }
    159             catch(IOException e){
    160                 e.printStackTrace();                
    161             }finally{
    162                 System.gc();
    163                 }
    164             }            
    165         }
    166 
    167 }
    复制代码

    三、说明

    1.线程数设置需要根据本集群硬件参数,实际测试得出。否则线程过多的情况下,总耗时反而是下降的。

    2.单笔提交数对性能的影响非常明显,需要在自己的环境下,找到最理想的数值,这个需要与单条记录的字节数相关。

    四、测试结果

    ---------开始MultThreadInsert测试----------

    线程:8插入数据:10000共耗时:1.328s
    线程:16插入数据:10000共耗时:1.562s
    线程:11插入数据:10000共耗时:1.562s
    线程:10插入数据:10000共耗时:1.812s
    线程:13插入数据:10000共耗时:2.0s
    线程:17插入数据:10000共耗时:2.14s
    线程:14插入数据:10000共耗时:2.265s
    线程:9插入数据:10000共耗时:2.468s
    线程:15插入数据:10000共耗时:2.562s
    线程:12插入数据:10000共耗时:2.671s
    MultThreadInsert:100000共耗时:2.703s
    ---------结束MultThreadInsert测试----------


    备注:该技术专题讨论正在群Hadoop高级交流群:293503507同步直播中,敬请关注。

    展开全文
  • 架构-分层模式案例

    千次阅读 2017-03-06 09:42:30
    架构模式是什么 软件架构模式,诞生于软件开发的最大难题——需求变更。由于需求变更,导致了大量项目因为超出预算的人力、时间而归于失败。软件开发成本有限的,但需求变更似乎是无限的,这成为了一个非常难...
     

    架构模式是什么

    软件架构模式,诞生于软件开发的最大难题——需求变更。由于需求变更,导致了大量项目因为超出预算的人力、时间而归于失败。软件开发成本有限的,但需求变更似乎是无限的,这成为了一个非常难解决的问题。


    软件需求变更的结果,基本上就是对于软件代码的修改。而软件代码的修改却是程序员们最头疼的事情。因为一些大型系统,其代码根本就无法完全看懂,即便能了解部分细节,在着手修改的时候,也会碰到“触一发而动全身”的问题:因为有些功能的修改,需要修改整个系统的很多部分,导致了无穷的BUG。


    另外一个致命的问题,就是在紧迫的时间内,对于代码的修改往往只能依赖有限的一个或几个程序员,只有他们对系统是最熟悉的。但是面临巨大的工作量,几乎无法让更多的程序员参与进来,其他人只能干瞪眼。一旦熟悉系统的程序员离职,有可能就代表了整个系统无法维护。即便是系统能分割给几个人负责,在“集成”几个部分的代码的时候,其调试和除错的工作,又常常是旷日持久的,因为那些从来没协作过的代码,隐藏着大量的误解和不兼容问题。——这一切的根源,其实只是一个最简单的事实,就是系统中对于“代码耦合”的结构问题。糟糕的代码耦合让整个系统变得难以理解、难以修改、难以分工、难以集成。


    针对代码耦合的问题,软件界进行了大量的理论研究和实践,最后发现:系统的架构设计,是改善耦合的最好方式。架构设计的本质,就是:

    1. 划分耦合的单位——也就是划分模块。系统应该划分成什么样的模块,代表了设计者对于系统应对的需求的基本理解。一旦能清晰的划分出模块了,其代码耦合就有了最基本的范围。而模块本身也是提示程序员理解系统的基本单位。


    2. 规范耦合的形式——代码耦合的形式有很多种,如直接调用、事件响应、消息队列等等,这些形式提供了代码耦合的不同特征。直接调用的代码在静态阅读的时候非常容易理解,而事件响应则提供了运行时耦合的好处。耦合的形式还有另外一层含义,就是代码耦合的规范:那些模块之间应该直接耦合,哪些不能耦合,是否应该加入中间层次等等。

    这两个关于耦合的设计,就形成了各种架构设计。


    在软件界多年的架构设计工作之后,人们总结出一些经验,这些经验被成为“架构模式”。架构模式包含了“名称”“适应场景”“模块定义”“模块关系”这几个部分。没有任何一种架构模式是万能的,所以每个模式都必须有“适应场景”。而模式本身的内容,就是通过“模式定义”和“模块关系”两个层面的规定来表现出来。除了模式的本身内容,为了理解某种特定的架构模式,人们还会附带上一些应用案例,好让学习者能通过实例来理解这种设计的真谛。


    最后,还会有些关于某种设计模式的实现手段——在面向对象的设计思想下,往往会使用一种或者多种“设计模式”来作为实现。当然只要是符合架构模式的耦合规定的,都可以成为某种架构模式的实践,但是使用软件业常见的“设计模式”,还是能比较轻松的去用代码来实现这些架构。



    分层模式

    下面我们开始第一个架构模式的介绍,先看一个案例:


    【此案例并非完全真实情况,有一定提炼修改成分】

    这是一个有着复杂功能的多人在线社区,其服务器端是我们需要讨论的重点。这个产品的服务器端必须满足多样的功能:玩家移动到不同的场景中,玩家可以换上不同的服装,可以互相加好友并且聊天,同时还有广播频道的聊天,每个玩家还有自己的资料库和背包,另外还有各种运营活动。


    在最初的开发过程中,我们针对每个需要开发的功能,建立了一个模块。这些模块通过单独和客户端、数据库的操作,完成所需功能。如果要开发新功能,就重新写一个这样的模块。这种架构设计在一开始是非常有效的,产品功能被不断的开发出来,模块的数量也在增多,但是也潜藏了一个问题。


    这个问题的爆发是随着一个叫做“任务系统”的功能而出现的。因为任务系统本质上是需要很多其他模块的功能提供支持。如需要玩家去某个场景(场景模块),获得某个东西(背包模块),然后添加一个好友(好友模块),或者换上某个服装,说一句话等等……这样的任务功能的实现,被迫要修改很多个模块的代码,因为每个模块都只有最基本的“自由使用”功能的代码,编程接口都仅仅是面向客户端的,而数据结果都是直接SQL到数据库的。这种需要组合的功能请求,以及获得功能的结果状况,都是其接口上没有的。这导致了非常复杂的,持续的代码修改。因为任务的内容可是时常会变化的哦!


    在分析了问题之后,我们决定重构整个架构,我们把架构从一字排开的设计,修改成为可以多个层次互相调用的模块。这些模块直接的接口,有面向客户端的,也有面向其他模块的,这样我们就能直接调用那些现成的功能,组合开发出更复杂强大的功能。不管任务系统如何变化,我们都可以不用重写那些已经实现的功能,这让整个系统成为可以应对这种需求变化的关键。


    实际上,这样的架构正是一个著名的架构模式——分层模式。

    分层模式的规定非常简单而有效:

    1. 每个模块都必须属于某个层次,提供给“第N+1层”(上层)服务;同时委派任务给“第N-1层”的模块。

    2. 任何一个模块,都不得逆层次调用:属于第N层的模块,不得调用(耦合)第N+1层或以上层次的模块。

    3. 任何一个模块,都不得跨层调用:属于第N层的模块,不应该调用第N-2层或更下层的模块。


    分层模式是架构中最基本的模式,但是也是我们开发中最被忽视的模式。我们开发中往往没有去定义代码的“层次”,仅仅以“功能”纵向划分模块,没有按实现层次横向切分。

    门面模式、策略模式都常常用来实现分层架构。

    上文所说的例子,后来改造成了分层模型:

    1)重复代码减少了,功能开发更快了——一顶层开发只需要学习下层类库,就可以开始开发;近似功能模块被统一,修BUG覆盖面更好。

    2)性能提升代码能更好的覆盖了——集中了通用实现代码,也集中了优化部分

    3)可以并行开发,资深人员负责底层,一般人员负责上层

    总结一下分层模式:

    “模式的模式”——强大同时灵活

    ★ 适应:集成不同类型功能 ——当我们需要把很多不同功能的代码集成起来的时候,这种模式提供了最合理的结构。能让我们的代码有足够的灵活性去应对需求变更。

    ★ 不适应:简单业务模型——如果系统本身不复杂(或者叫做可预期的修改很少),建立各种层次,然后为了符合层次间调用的规定,会增加很多不必要的代码,陷入过度设计的泥坑。

    ★ 方法论:以业务逻辑特征建模 ——使用分层模式,往往需要我们在大脑里对问题领域进行层次抽象,这种抽象最可信赖的原则,就是按照业务逻辑去做。比如现实业务中有一个角色,我们就建立一个角色的模块;如果我们有一个场景,就以此为名建立一个这样的模块……。以业务逻辑建立的模块,本身也会让系统更容易被理解,因为在代码里能找到和现实中一一对应的概念。

    ★ 设计模式实现:

    ★ 门面模式 ——我们对于每个模块或者每个层次都会设计一个“门面”来降低耦合的复杂程度。

    ★ 策略模式——抽象层次会隐藏底层的实现细节,这就是策略模式最基本的设计,我们往往会把上层作为功能接口,下层作为可选的策略来实现。



    展开全文
  • 浅谈并行编程中的任务分解模式

    千次阅读 2014-06-04 16:59:11
     并行编程使用线程来使得多个操作能够同时运行。... 不熟悉并行编程的开发者通常对例如面向对象的传统的编程模式感到非常适应。在传统的编程模式下,程序以预先定义的起点开始运行,譬如main函数,然后接连地做完
    
    并行编程使用线程来使得多个操作能够同时运行。并行编程主要包括应用程序中线程设计,开发和部署以及线程间相互协调和各自的操作。

          在下文中我们将讨论怎样分割适合线程化大小的编程任务来多任务化一个应用程序。

    设计线程

          不熟悉并行编程的开发者通常对例如面向对象的传统的编程模式感到非常适应。在传统的编程模式下,程序以预先定义的起点开始运行,譬如main函数,然后接连地做完一系列任务。如果程序依赖用户交互,主要的工作代码通常被封装在一个处理用户事件的循环里。

          从一个约定事件开始,譬如点击按钮,程序运行一段已经制定的顺序行为,最终以等待用户下个动作结束。

          当设计这样的程序时,程序员喜欢一个相对简单的编程模式因为在任意一段给定的时间内只有一个事件发生。如果程序任务必须按某种方式顺序运行, 程序员必须在这些事件上特意安排顺序。在这个过程的任一时刻,程序运行一步接着下一步,最终基于预先确定的参数到达一个预见的结果。

    从这种线性的模式到并行编程模式,程序设计者必须重新思考程序的过程流。相比顺序执行序列限制,程序员应该识别出那些能被并行化的行为。

          要这样做,他们必须把程序看作一组相互间有依赖关系的任务。把程序分解成一些独立的任务并识别这些任务间的依赖性。这个过程被称为分解。

          一个问题有许多分解方式: 按任务,数据,或者按数据流。下面的表总结了这些分解的形式。您将很快看到,这些不同分解形式对应了不同的编程行为。

    任务分解

          按功能分解一个程序被称为任务分解。这是一种实现并行执行最简单的方式。使用这种方法,每个任务被按目录分类。

          如果它们中的两个能同时运行,它们会被程序员按此调度。以这种方式并行运行任务通常需要对每个函数做小量修改来避免冲突,并指出这些任务已经不再连续。

          以园艺工作举例,任务分解会建议园丁按工作本身的属性分配任务:如果两个园丁到达一个客户家,一个修剪草坪,另一个铲除杂草。修剪草坪和铲除杂草是两个被分开的功能。

          要完成这两个功能,园丁们需要确保他们之间相互协调,这样铲除杂草的园丁就不会坐在待修剪草坪的中间。

          举个编程的例子,一个任务分解的典型案例是文字处理软件,譬如微软的Word。当用户打开一个很长的文档的时候,他(她)能够马上开始输入文字。当用户输入文字时,文档分页在后台发生,于是他(她)能够很容易地看到状态栏中页数的增加。

          文档输入和分页是两个独立的任务,程序员按功能将它们分开来并行运行。如果程序员没有这样设计,用户将不得不在能够输入任何文字之前等待整个文档被分页。有些朋友可能回忆起这种现象在早期的个人电脑文字处理器中非常常见。

    数据分解

          数据分解,也被认为是数据级并行,将任务按它们处理的数据进行分解,而不是按照任务本身的性质。使用数据分解的程序通常有许多线程在执行同样的任务,只是处理的数据项不同。

          举个例子,假设在一个大的电子数据表里计算值。相比一个线程执行所有的计算,数据分解会建议有两个线程,每个执行一半的计算量,或者n个线程执行1/n的工作量。

          如果园丁应用数据分解来分解他们的任务,他们两个会同时修剪一半的草坪,然后两个人分别铲除一半的杂草。在计算领域,决定哪一种分解形式更高效取决于系统的限制。

          举例说,如果需要修剪草坪的地块非常小以至于没必要有两个人来修剪草坪,修剪草坪这个任务最好只被分配给一个园丁做,那么任务分解在这一步是最好的选择。数据分解或许适用于其它的任务序列,譬如当修剪草坪完成后,两个园丁并行地来铲除杂草。

          随着处理器核心数目的增加,数据分解使得任务处理规模增加。这允许在同样的时间内做更多的工作。

          举园丁的例子,假设有另外两个园丁加入了工作。相比分配所有四个园丁到一个地块工作,我们不如分配两个新的园丁去另一个地块,非常有效地增加我们总的任务处理量。

          假设两位新园丁和两位老园丁能够做同样多的工作,两个地块的大小也是一样的,我们已经在同样的时间内把工作量翻倍了。

    数据流分解

          许多时候,当分解一个问题时,关键不是任务应该做什么事情,而是数据在不同任务中怎样传递。在这些情况下,数据流分解将问题按数据在任务中传递的方式来分解。

          生产者/消费者问题是数据流影响程序并行执行能力的著名例子。这里,一个生产者任务的输出,成为另一个消费者的输入。两个任务被不同的线程执行,直到生产者完成他的部分工作,消费者不能开始工作。

    依然引用园丁的例子,一个园丁准备工具,譬如他承担为割草机加油,清扫剪刀等类似的任务来提供这些工具给另两个园丁使用。直到这个准备步骤基本结束,其他园丁的园艺工作才能开始。

          由第一个任务引起的延迟为第二个任务产生一个暂停,在此之后两个任务才能并行运行。在计算机领域这样的模式经常发生。

         在常见的编程任务里,生产者/消费者问题在多个典型的场景发生。譬如,必须对读文档做回应的程序就符合这种场景:文件的输入/输出结果成为下一步可能被线程化的工作的输入。下一步直到读完或读到其他处理需要的足够信息才会开始执行。另一个编程的例子是分析:一个输入文件必须在后端操作之前被分析或者语义分析,譬如编译器的代码生成。

    生产者/消费者问题有许多需要注意的方面:

    1) 如果这种模式没有正确地执行,消费者和生产者间产生的依赖性会引起重大的延迟。一个性能敏感的设计需要充分理解依赖关系的性质以减小延迟的影响。这也是为了避免消费者线程空闲等待生产者线程的情况。

    2) 在完美的情况下,生产者和消费者间的传递是完全"清洁"的,就像在文件分析器的例子中一样。输出是上下文相关的,消费者不需要知道生产者的任何事情。然而在很多时候,生产者和消费者并不享受如此干净的任务分割,安排他们间的互动需要非常仔细的计划。

    3) 如果当生产者完全做好后消费者开始加工,那么当其他线程忙着工作时一个线程就保持空闲。这个问题破坏了一个并行处理的重要目标,那就是负载均衡以使得所有能用的线程保持忙碌。由于线程间的逻辑关系,要保持线程平等地被占用非常困难。

          下面,我们看看流水线模式,它允许开发者以可升级的模式解决生产者/消费者问题。

    不同分解的含义

          不同的分解具有不同的优势。如果目标是使编程简便,任务能够清楚地按功能分割,那么任务分解通常更合适。

          数据分解增加了一些额外的代码级复杂度,因此他专供数据非常容易分解而性能又非常重要的情况使用。

    线程化程序的最常见原因就是性能。在这种情况下,分解方式的选择就更加困难。在许多情况下,选择依赖于问题的领域:一些任务明显更适合于其中一种分解方式。

          但是一些任务没有明显的偏向。譬如视频流中的图像处理。在帧与帧间没有依赖的格式,你需要作出分解模式的选择。他们应该选择任务分解么,那样一个线程解码,另一个线程配色,诸如此类?或者选择数据分解,每个线程做一帧上的所有工作,然后一起开始处理新的一帧?

          回到园丁的例子:如果两个园丁需要修整两块草坪和铲除两块花园的杂草,他们应该怎样工作?是应该一个园丁只修剪草坪,也就是他们选择基于任务的分解呢?还是两个人应该同时修剪草坪然后同时铲除杂草?

          在一些情况下,答案很快显现。例如当一个资源限制存在,譬如只有一个割草机。其它情况下每一个园丁都有一个割草机,答案只能通过仔细分析行为要素来得出。在园丁的例子中,任务分解看起来更好,因为如果只有一个割草机在使用,开始的割草时间就被节省了。

          最终,你通过仔细的计划和测试来为你的应用程序使用并行编程作出正确的选择。 根据经验估计在你决定并行程序设计时比标准的单线程编程中扮演更加重要的角色。

    你将面对的挑战

          使用线程通过允许两个或多个行为同时发生使得你显著改进性能。然而,开发者不能不认识到线程增加了复杂性度量,需要细致的考虑来正确引导。

          这种复杂度源于程序中多于一个行为发生的自身性质。管理同步行为和他们可能的交互使你面对下面四种问题:

    1) 同步是两个或多个线程协调他们行为的过程。譬如,一个线程在继续运行前等待另一个完成任务。

    2) 交互代表与线程间交换数据相关的带宽和延迟问题。

    3) 负载均衡表示任务在多个线程间的分配,因此他们都处理基本同样的工作量。

    4) 可扩展性是当软件在更先进的系统上运行时高效利用许多线程的挑战。譬如,如果一个程序被编写来充分利用四核处理器,当它在一个八核处理器上运行时它是否能适当地扩展?

          上述每个问题都必须被仔细地处理来最大化程序的性能。

    并行编程模式

          对于多年编写面向对象程序的程序员,他们使用设计模式来逻辑地设计他们的应用程序。并行编程和面向对象编程没有什么不同,并行编程问题通常对应于许多知名的编程模式之一。

          下面的表格显示了一些常见的并行编程模式和他们对应的上述分解类型。

    在这部分,我们将提供每种模式及其适用的问题种类的简要概述,包括:

    1) 任务级并行编程模式。在许多情况下,完成并行执行的最佳方法是直接关注任务本身。在这种情况下,任务级并行模式最合适。这种模式下,问题被分解成一组独立操作的任务。

    通常移除任务间的依赖性或使用复制来分离依赖性是必要的。适合这种模式的问题包括线程间没有依赖性,或线程间的依赖性可从每一个线程中移除。

    2) 分而治之模式。在分而治之模式中,问题被分成许多并行的子问题。每个子问题被单独解决。当每个子问题被解决时,结果合计到最后的结果中。因为每个子问题都能被单独解决,这些子问题有可能被并行执行。

    分而治之的方法被广泛应用于诸如合并分类的算法。这些算法非常容易被并行化。这种模式很好地处理了负载均衡,这点对缓存的有效利用非常重要。

    3) 几何分解模式。几何分解模式基于正在解决问题的数据结构的并行化。在几何分解中,每个线程负责操作数据块。这种模式可能适用于诸如热流和声波传播之类的问题。

    4) 流水线模式。流水线模式的意思类似于一条工厂的产品装配线。这种寻找并发的方式使计算被分割成一系列阶段,每个线程在不同的阶段同时工作。

    5) 波阵面模式。波阵面模式在处理二维网格中延对角线的数据元素时非常有用。如下图所示。

    上图中的数字解释了数据元素被处理的顺序。譬如对角线的元素包括数字3是独立于之前被处理的数字元素1和2的。

          上图中阴影中的数据元素表示数据已经被处理。在这种模式下,减小每个线程的空闲时间非常关键。负载均衡在此种模式中非常关键。

          更加详细的并行编程设计模式的介绍请参考"并行编程模式"(Mattson 2004) 一书。

    *本文观点引自英特尔公司系统架构师Shameem Akhter和高级软件工程师Jason Roberts的文章

    展开全文
  • 这些流程模式均在BPMN2.0规范中有明确的定义,activiti、flowable、camunda等开源工作流引擎也都支持这些模式,以下重点介绍会签流程、或签流程、分支流程、并行流程这四种流程模式。 一、会签流程 1、适用场景 会签...
  • IBM 在互联网医疗领域的定位:怎么样利用数据挖掘和人工智能的技术,从海量的医疗... 计算机处理能力的飞跃发展:Hadoop、Spark这样的并行计算,还是像GPU、FPGA这样的硬件加速发展,计算机的处理能力有了性能上的飞...
  • Hadoop的搭建方式有三种,本地模式,伪分布模式和完全分布式模式,这篇文章我们简单介绍了一下本地模式下怎样搭建Hadoop环境以及运行简单的案例,在后面会陆续介绍伪分布模式下和完全分布式模式下Hadoop的搭建,有...
  • 接着之前写的并行算法parallel包,parallel相比foreach来说,相当于是foreach的进阶版,好多东西封装了。而foreach包更为基础,而且可自定义的内容很多,而且实用性比较强,可以简单的用,也可以用得很复杂。笔者将...
  • 问题导读1.微服务有什么特点?2.本文介绍了哪些案例?3.你认为事件驱动的微服务、容器、Kubernetes和机器学习结合可以有哪些应用?随着当今业务和技术的快速变化,开...
  • 数据并行

    2019-04-28 20:29:23
    1.并行和并发 2.并行化流操作 3.模拟掷骰子 4.性能 5.总结 1.并行和并发 并发是两个任务共享时间段,并行则是两个任务在同一时间发生,比如运行在多核CPU上。如果一个程序要运行两个任务,并且只有一个CPU给...
  • .NET并行库测试实例

    千次阅读 2009-03-04 20:31:00
    .NET并行库测试实例并行库存应用场景: 并行计算首要目的是提高CPU的计算能力,简单说程序应该是以CPU密集型运算为主的,如果你的程序是IO(磁盘和网络)密集型运算,并行计算并不能对你的程序有多大的提高。...
  • 深度学习及并行化实现概述

    千次阅读 2018-02-08 21:25:50
    深度学习及并行化实现概述摘要: 深度学习可以完成需要高度抽象特征的人工智能任务,如语音识别、图像识别和检索、自然语言理解等。深层模型是包含多个隐藏层的人工神经网络,多层非线性结构使其具备强大的特征表达...
  • 本文针对并行和并发收集统计信息的相关知识内容以及部分案例进行介绍,并重点介绍并发统计信息收集。
  • 并行信号处理技术-序

    千次阅读 2017-09-11 22:27:38
    下面几篇将连载并行信号处理技术,内容来自于我原来的工作,略作总结。 背景和意义 然而随着材料科学和电子对抗技术发展,雷达面临着前所未有的挑战。隐身、低空、高速、高机动目标对雷达的探测能力提出了新的要求...
  • 深度学习和并行化实现

    千次阅读 2018-02-07 14:54:29
    深层模型的并行化框架和训练加速方法是深度学习走向实用的重要基石,已有多个针对不同深度模型的开源实现,Google、Facebook、百度、腾讯等公司也实现了各自的并行化框架。深度学习是目前最接近人脑的智能学习方法,...
  • 浅谈并行编程中的任务分解模式提交新文章 转自http://software.intel.com/zh-cn/articles/discussion-on-parrallel-programming-decomposition/?cid=sw:prccsdn604浅谈并行编程中的任务分解模式提交新文章作者Hai
  • ajax请求串行和并行的问题

    千次阅读 2017-05-30 23:48:57
    2.如何让他们并行执行,然后三个请求都执行完成后,再执行某个操作? //串行执行分两种。 //一是用同步模式async: false,三个ajax请求连着写就可以了。 $.ajax({ url: "ajax请求1", async: false,
  • 终于开始攻克并行这一块了,有点小兴奋,来看看网络上R语言并行办法有哪些。 同时并行时对内存的消耗极大,超级容易爆发内存问题,而且R的内存问题一直都是R很难解决的问题,这边笔者也把看到的一些方式列出来。 ...
  • 并行学习总结

    万次阅读 2016-02-22 21:33:09
    Thread的提出有一部分原因就是来因为IPC效率低下,像这样使用多进程仅仅是把本来应该自己做的同步交给了OS去完成。而且最终数据要汇集到一个进程去最终完成,这样的话效率最终很可能就被这最后一个进程限制住,从而...
  • 让API并行调用变得如丝般顺滑的绝招

    万次阅读 多人点赞 2020-12-29 12:17:18
    但批量查询还是同步模式,下面介绍如果使用CompletableFuture来实现异步并发调用,直接用原生的CompletableFuture也可以,但是编排能力没有那么强,这里我们选择一款基于CompletableFuture封装的并行编排框来实现,...
  • JAVA8新特性[第五季]-并行流与串行流

    千次阅读 2017-08-20 22:16:14
    案例 1 java8之前 ForkJoin的计算 2 使用普通for 循环 3 java8中 ForkJoin计算 一、什么是并行并行流 : 就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流。 Java 8 中将并行...
  • ML之XGBoost:XGBoost算法模型(相关配图)的简介、关键思路、代码实现(目标函数/评价函数)、安装、使用方法、案例应用之详细攻略 目录 XGBoost算法模型(相关配图)的简介 XGBoost算法关键思路 XGBoost算法...
  • 并行与分布式计算复习大纲 华南农业大学

    千次阅读 多人点赞 2021-01-04 18:37:53
    1. 为什么要并行编程 分布和并行计算的区别(重点) 答:并行(如果针对线程进程而言的问题的话,并行就是共享计算机CPU资源)。单机多核,问题并行编程;分布:网络连接,对外以整体提供服务 并行和并发的区别...
  • Junit5的并行执行

    千次阅读 2020-06-28 19:30:03
    默认情况下,junit测试是在一个线程中串行执行的,从5.3开始支持并行测试。首先需要在配置文件junit-platform.properties中配置如下参数: junit.jupiter.execution.parallel.enabled=true 但是仅仅开启这个参数是...
  • mongodb11天之屠龙宝刀(六)mapreduce:mongodb中mapreduce原理与操作案例 原文连接:直通车 一 Map/Reduce简介 MapReduce 是Google公司的核心模型,用于大规模数据集(大于1TB)的并行计算。“映射(Map)”与...
  • 并行处理和FME:FME2019重新设计

    千次阅读 2019-01-30 13:40:44
    并行处理在性能方面可能是一个大问题。现代计算机具有多个内核,并且这些...我们看到支持案例和测试结果表明我们应该重新设计并行处理设置; 所以对于FME 2019来说,这正是我们所做的! 并行处理如何在2019...
  • MapReduce设计模式学习

    千次阅读 2016-03-12 19:15:42
    一:概要模式 1:简介 概要设计模式更接近简单的MR应用,因为基于键将数据分组是MR范型的核心功能,所有的键将被分组汇入reducer中 本章涉及的概要模式有数值概要(numerical summarization),倒排索引...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,521
精华内容 13,808
关键字:

并行模式的案例