精华内容
下载资源
问答
  • MPI并行程序设计原理--基础知识

    千次阅读 2019-11-29 15:22:15
    MPI并行程序设计原理–基础知识 前言 消息传递并行程序设计 指用户必须通过显式地发送和接收消息来实现处理机间的数据交换。在这种并行编程中,每个并行进程均有自己独立的地址空间,相互之间访问不能直接进行,必须...

    MPI并行程序设计原理–基础知识

    前言

    消息传递并行程序设计

    指用户必须通过显式地发送和接收消息来实现处理机间的数据交换。在这种并行编程中,每个并行进程均有自己独立的地址空间,相互之间访问不能直接进行,必须通过显式的消息传递来实现。
    这种编程方式是大规模并行处理机(MPP)和机群( luster)采用的主要编程方式。
    并行计算粒度大,特别适合于大规模可扩展并行算法。
    由于消息传递程序设计要求用户很好地分解问题,组织不同进程间的数据交换,并行计算粒度大,特别适合于大规模可扩展并行算法。
    消息传递是当前并行计算领域的一个非常重要的并行程序。

    什么是MPI?

    Massage Passing Interface:是消息传递函数库的标准规范,由MPI论坛开发,支持 Fortran和C。
    MPI是一种新的库描述,不是一种语言。共有上百个函数调用接口,在 Fortran和C语言中可以直接对这些函数进行调用。
    MPI是一种标准或规范的代表,而不是特指某一个对它的具体实现。
    MP是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准。

    C中的MPI约定

    1.必须包含mpi.h头文件。
    2.MPI_ 前缀,只有MPI以及MPI_标志后的第一个字母大写,其余小写。

    MPI中基本函数

    1.MPI_Init(int *argc,char *argv)
    —MPI程序的第一个调用,完成MPI程序的所有初始化工作。所有的MPI的第一条可执行语句都是这个语句。
    –  启动MPI环境,标志并行代码的开始。
    –  并行代码之前,第一个MPI函数(除MPI_Initialize()外)。
    –  main函数必须带参数运行,否则出错。

    2.MPI_Finalize(void)
    –  MPI程序的最后一个调用,结束MPI程序的运行,是MPI程序的最后一条可执行语句。否则程序的运行结果是不可预知的。
    –  标志并行代码的结束,结束除主进程外的其他进程。
    –  之后串行代码仍可在主进程(rank=0)上运行。

    3.int MPI_Comm_size (MPI_Comm comm ,int* size )
    –  获得进程个数 size。
    –  指定一个通信子,也指定了一组共享该空间的进程, 这些进程组成该通信子的group(组)。
    –  获得通信子comm中规定的group包含的进程的数量。

    4.int MPI_Comm_rank (MPI_Comm comm ,int* rank)
    –  得到本进程在通信空间中的rank值,即在组中的逻辑编号(该 rank值为0到p-1间的整数,相当于进程的ID。)

    5.int MPI_Send( void *buff, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
    – void *buff:你要发送的变量。
    – int count:你发送的消息的个数(注意:不是长度,例如你要发送一个int整数,这里就填写1,如要是发送“hello”字符串,这里就填写6(C语言中字符串未有一个结束符,需要多一位))。
    – MPI_Datatype datatype:你要发送的数据类型,这里需要用MPI定义的数据类型,可在网上找到,在此不再罗列。
    – int dest:目的地进程号,你要发送给哪个进程,就填写目的进程的进程号。
    – int tag:消息标签,接收方需要有相同的消息标签才能接收该消息。
    – MPI_Comm comm:通讯域。表示你要向哪个组发送消息。

    6.int MPI_Recv( void *buff, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
    – void *buff:你接收到的消息要保存到哪个变量里。
    – int count:你接收消息的消息的个数(注意:不是长度,例如你要发送一个int整数,这里就填写1,如要是发送“hello”字符串,这里就填写6(C语言中字符串未有一个结束符,需要多一位))。它是接收数据长度的上界. 具体接收到的数据长度可通过调用MPI_Get_count 函数得到。
    – MPI_Datatype datatype:你要接收的数据类型,这里需要用MPI定义的数据类型,可在网上找到,在此不再罗列。
    – int dest:接收端进程号,你要需要哪个进程接收消息就填写接收进程的进程号。
    – int tag:消息标签,需要与发送方的tag值相同的消息标签才能接收该消息。
    – MPI_Comm comm:通讯域。
    – MPI_Status *status:消息状态。接收函数返回时,将在这个参数指示的变量中存放实际接收消息的状态信息,包括消息的源进程标识,消息标签,包含的数据项个数等。

    消息发送与接收函数的参数的一些重要说明。
    1.MPI标识一条消息的信息包含四个域:
    –  源:发送进程隐式确定,进程rank值唯一标识.
    –  目的:Send函数参数确定.
    –  Tag:Send函数参数确定.
    –  通信子:缺省MPI_COMM_WORLD
    •  Group:有限/N,有序/Rank [0,1,2,…N-1]
    •  Contex:Super_tag,用于标识该通讯空间.
    2. buffer的使用
    buffer必须至少可以容纳count个由datatype指明类型的数据. 如果接收buf太小, 将导致溢出、 出错
    3. 消息匹配
    –  参数匹配source,tag,comm/dest,tag,comm.
    –  Source == MPI_ANY_SOURCE: 接收任意处理器来的数据(任意消息来源).
    –  Tag == MPI_ANY_TAG: 匹配任意tag值的消息(任意tag消息).
    4. 在阻塞式消息传送中不允许Source == dest,否则会导致死锁。
    6. 消息传送被限制在同一个通信域内。
    7. 在send函数中必须指定唯一的接收者。

    MPI程序的编译与执行

    需要已经装好MPICH

    以Hello.c文件为例
    编译:

    mpicc -o hello hello.c
    --生成可执行文件hello	
    

    执行:

    mpirun -np 4 hello
    --4 指定np的实参,表示进程数,由用户指定。
    
    展开全文
  • 第一部分我们介绍并行和并发程序原理;第二部分介绍的是并行程序设计;第三部分介绍并发程序设计。 实例:大数组元素的求和 思想:给出4个线程同时对数组的1/4求和。 注意:这是一个低级的算法 创建4个...

    当处理器的性能的发展受到各方面因素的限制的时候,计算机产业开始用多处理器结构实现并行计算来提高计算的效率。我们使用多处理器共享存储器的方式实现了多处理器编程,也就是多核编程。当然在这样的系统结构下我们面临着各种各样的挑战,例如如何协调各个处理器之间的数据调度以及现代计算机系统固有的异步特征等等。

    在接下来的一系列文章中,我将会介绍一些基础的原理以及并行程序的设计和并发程序的设计及实现,写这篇文章是对近期学习课程的总结,方便自己温故时习,感谢USTC付明老师的《多核并行计算》课程,了解更多推荐《The Art of Multiprocessor Programming, Revised Reprint》。

    实例:大数组元素的求和

    思想:给出4个线程同时对数组的1/4求和。

    • 注意:这是一个低级的算法
    • 创建4个线程,每个线程负责部分的工作
    • 调用start(),启动每个线程并行的运行
    • 使用join()方法等待每个线程运行结束
    • 将4个结果相加在一起
    class SumThread extends java.lang.Thread {
      int lo, int hi, int[] arr; // arguments
      int ans = 0; // result
      SumThread(int[] a, int l, int h) { … }
      public void run(){ … } // override
    }
    
    int sum(int[] arr){// can be a static method
      int len = arr.length;
      int ans = 0;
      SumThread[] ts = new SumThread[4];
      for(int i=0; i < 4; i++){// do parallel computations
        ts[i] = new SumThread(arr,i*len/4,(i+1)*len/4);
        ts[i].start(); //必须使用start(),而不是run()方法
      }
      for(int i=0; i < 4; i++) { // combine results
        ts[i].join(); // wait for helper to finish!
        ans += ts[i].ans;
      }
      return ans;
    }
    

    join()方法使得调用者阻塞,直到receiver 完成了执行;
    线程的启动需要用start(),而不是run()

    Fork-join framework

    Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

    我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算1+2+…+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇总这10个子任务的结果。

    这里写图片描述

    • Fork-join 程序不需要关注线程间的共享内存

    EX:求一个数组的最大值。

    多线程方法:

    public class MyThread implements Runnable {
    
        //下面两个静态成员变量需要通过用关键字synchronized修饰 的方法来访问
        private volatile static int max = Integer.MIN_VALUE;            //初始最大值
    
        //下面为成员变量,每个线程对象私有
        private int[] nums;            //待查找数组
        private int low;                  //当前线程对象需要处理的数组开始下标
        private int high;                 //当前线程对象需要处理的数组结束下标
    
        //构造方法,传入待查找数组、开始下标和结束下标
        public MyThread(int[] nums, int low, int high){
            this.nums = nums;
            this.low = low;
            this.high = high;
        }
    
        @Override
        public synchronized void run() {
    
            for(int i=low;i<=high;i++)
            {
                if(nums[i] > max)
                {
                    MyThread.setMax(nums[i]);
                }
            }
    
        }
    
        public static synchronized int getMax() {
            return max;
        }
    
        public static synchronized void setMax(int max) {
            MyThread.max = max;
        }
    
    }

    Fork-join框架:

    public class ForkThread extends RecursiveTask<Integer> {
    
        private static final int SEQUENTIAL_THRESHOLD = 5;//子数组到分割最终大小
    
        private final int[] data;
        private final int start;
        private final int end;
    
    public ForkThread(int[] data, int start, int end) {
      this.data = data;
      this.start = start;
      this.end = end;
    }
    
    public ForkThread(int[] data) {
      this(data, 0, data.length);
    }
    
        @Override
        protected Integer compute() {
            final int length = end - start;
            if (length < SEQUENTIAL_THRESHOLD) {
                return computeDirectly();
            }
            final int split = length / 2;
            final ForkThread left = new ForkThread(data, start, start + split);
            left.fork();
            final ForkThread right = new ForkThread(data, start + split, end);
            return Math.max(right.compute(), left.join());
        }
    
    private Integer computeDirectly() {
      /*System.out.println(Thread.currentThread() + "computing: " + start
                         + " to " + end);*/
      int max = Integer.MIN_VALUE;
      for (int i = start; i < end; i++) {
        if (data[i] > max) {
          max = data[i];
        }
      }
      return max;
    }
    
        public static void main(String[] args) {
            // create a random data set
            final int[] data = new int[10000];
            final Random random = new Random();
            for (int i = 0; i < data.length; i++) {
                data[i] = (int)Math.floor((random.nextDouble()*100000.0)); 
                System.out.println(data[i]);
            }
            /*int data[] = new int[10000];
            for(int i=0;i<10000;i++)
                data[i] =(int) Math.random()*10000;*/
    
            // submit the task to the pool
            final ForkJoinPool pool = new ForkJoinPool(4);
            final ForkThread finder = new ForkThread(data);
    //      System.out.println(pool.invoke(finder));
        }
    }

    Main方法线程:

    public class SearchMax {
    
        /**
         * @param args
         */
        //初始化数组
        public static int[] InitialArr(){
            final int[] data = new int[10000];
            final Random random = new Random();
            for (int i = 0; i < data.length; i++) {
                data[i] = (int)Math.floor((random.nextDouble()*100000.0)); 
            }
            return data;
        }
        //分治法
        public static long DivideMax(int arr[]){
    
            int size = arr.length;
            long startTime=System.nanoTime();
            Thread t1 = new Thread(new MyThread(arr,0,size/2));
            Thread t2 = new Thread(new MyThread(arr,size/2+1,size-1));
    
            t1.start();
            t2.start();
    
            try {
                t1.join();
                t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long endTime=System.nanoTime();
            System.out.println( "分治法: "+MyThread.getMax());
    
            return (endTime-startTime);
        }
    
    
        //顺序查找
        public static long OrderMax(int arr[]){
    
            int size = arr.length;
            int ret = 0;
            long startTime=System.nanoTime();
            for(int i=0;i<size;i++){
                if(arr[i]>ret)
                    ret = arr[i];
            }
            long endTime=System.nanoTime();
            System.out.println( "顺序查找: "+ret);
            return (endTime-startTime);
        }
    
        //Fork-Join框架
        public static long ForkMax(int arr[]){
    
            int ret = 0;
            long startTime=System.nanoTime();
            // submit the task to the pool
            final ForkJoinPool pool = new ForkJoinPool(4);
            final ForkThread finder = new ForkThread(arr);
    
            ret = pool.invoke(finder);
            long endTime=System.nanoTime();
            System.out.println( "Fork_join: "+ret);
            return (endTime-startTime);
        }
    
        public static void main(String[] args) {
    
            int data[] = InitialArr();
            System.out.println("分治法花费时间 "+DivideMax(data)+" ns");
            System.out.println("顺序查找花费时间 "+OrderMax(data)+" ns");
            System.out.println("Fork_Join花费时间 "+ForkMax(data)+" ns");
    
        }
    
    }

    运行结果:

    这里写图片描述

    设计一个Fork/Join框架的步骤:

    第一步:分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停的分割,直到分割的子任务足够小;

    第二步:执行任务并合并结果,分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里分别获取任务执行,子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。

    Fork/Join框架使用两个类来完成以上两件事:

    (1)ForkJoinTask:我们要使用Fork Join框架,必须首先创建一个Fork Join任务,它提供在任务中执行fork() 和join()操作的机制,通常情况下我们不需要继承ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供以下两个子类:

    • RecursiveAction:用于没有返回结果的任务。

    • RecursiveTask:用于有返回结果的任务。

    (2)ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行,任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。

    Fork/Join框架的异常处理:

    Fork JoinTask在执行的时候可能会抛出异常,但是我们没办法在主线程里直接捕获异常,所以Fork JoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过Fork JoinTask的getException方法获取异常,使用如下代码:

    if(task.isCompletedAbnormally())
    {
    System.out.println(task.getException());
    }
    getException方法返回Throwable对象,如果任务被取消了则返回CancellationException,如果任务没有完成或者没有抛出异常则返回null。

    EX:大数组求和

    class SumArray extends RecursiveTask<Integer> {
      int lo; int hi; int[] arr; // arguments
      SumArray(int[] a, int l, int h) { … }
      protected Integer compute(){// return answer
        if(hi – lo < SEQUENTIAL_CUTOFF) {
          int ans = 0;
          for(int i=lo; i < hi; i++)
            ans += arr[i];
          return ans;
        } else {
          SumArray left = new SumArray(arr,lo,(hi+lo)/2);
          SumArray right= new SumArray(arr,(hi+lo)/2,hi);
          left.fork();
          int rightAns = right.compute();
          int leftAns  = left.join(); 
          return leftAns + rightAns;
        }
      }
    }
    static final ForkJoinPool fjPool = new ForkJoinPool();
    int sum(int[] arr){
      return fjPool.invoke(new SumArray(arr,0,arr.length));
    }
    

    算法设计

    展开全文
  • 并行编程入门

    千次阅读 2016-10-14 20:10:38
    1. 并行编程简介 2. MapReduce 2.1 MapReduce简介 2.2 MapReduce框架 2.3 Hadoop介绍 2.4 Hadoop基本类 2.5 Hadoop编程实例1.并行编程简介1.1.并行编程作用,用途商业用途,科学计算,大数据分析1.2....

    目录

    1. 并行编程简介
    2. MapReduce
      2.1 MapReduce简介
      2.2 MapReduce框架
      2.3 Hadoop介绍
      2.4 Hadoop基本类
      2.5 Hadoop编程实例

    #1.并行编程简介
    ##1.1.并行编程作用,用途
    商业用途,科学计算,大数据分析

    ##1.2.并行编程兴起原因
    目前的串行编程的局限性
    使用的流水线等隐式并行模式的局限性
    硬件的发展
    ##1.3.并行算法设计原则步骤
    a.分析问题
    b.分解问题
            其中分解方法有:
            数据分解
            递归分解
            探测性分解
            推测性分解
            混合分解
    c.根据分解方法,产生任务
    d.将任务映射到处理器上
    e.要注意的问题:
            减少任务之间的交互(任务粒度,任务的依赖)
            负载均衡(静态均衡和动态均衡)

    ###1.4并行算法模型
            数据并行模型
            任务图模型
            工作池模型(任一个任务可映射到任一个处理器上)
            主-从模型
    ###

    ##1.5.基本通信操作(单端口,双向)
    对于不同的操作,对于不同的设备模型,有如下几种组合:
    a.一对多广播及多对一归约(一传到二,然后二传到4)
    环或线性阵列:
    格网:
    超立方体:
    b.多对多广播 及 多对多归约
    环或线性阵列:
    格网:
    超立方体:
    d.全归约 及 前缀和
    环或线性阵列:
    格网:
    超立方体:
    e.散发及 收集归约
    环或线性阵列:
    格网:
    超立方体:
    f.循环移位
    环或线性阵列:
    格网:
    超立方体:

    ##1.6.解析建模
    模型需要考虑的因素有:

    • 开销分析
    • 性能度量
              执行时间,加速比,总并行开销,效率,成本
    • 粒度影响
    • 系统可扩展性
      ###1.7使用消息传递模式编程
      使用MPI API 进行编程
    MPI,消息传递接口
    int MPI_Init(int *argc,char ***grgv)
    
    int MPI_Finalize()
    
    int MPI_Comm_size(MPI_Comm comm,int * size):用size返回comm域中进程数目
    
    int MPI_Comm_rank(MPI_Comm comm,int * rank):用rank返回comm域中进程等级(0-size-1)
    
    int MPI_Send(void buf,int count,MPI_Datatype datatype,int dest,int tag,MPI_comm comm);
    
    int MPI_Recv(void buf,int count,MPI_Datatype datatype,int source,int tag,MPI_comm comm,MPI_status status);
    
    int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) 
    

    ###

    #2.MapReduce
    参考文献:
    http://www.open-open.com/lib/view/open1328763069203.html
    http://www.wnt.com.cn/html/news/tophome/top_xytd/top_xytd_jswz/bbs_service/20130711/111140562.html
    http://blog.csdn.net/geekcome/article/details/9024419
    http://www.cnblogs.com/biyeymyhjob/archive/2012/08/12/2633608.html
    http://www.educity.cn/wenda/578905.html
    http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop1/#ibm-pcon
    http://wiki.apache.org/hadoop/
    http://hadoop.apache.org/
    http://research.google.com/archive/mapreduce-osdi04.pdf

    IBM Hadoop分布式并行编程系列:
    第一部分:http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop1/
    第二部分:http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop2/
    第三部分:http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop3/
    http://www.educity.cn/wenda/578905.html
    http://datalife.iteye.com/blog/930318

    ##2.1MapReduce简介
            MapReduce 是 Google 公司的核心计算模型,它将复杂的运行于大规模集群上的并行计算过程高度的抽象到了两个函数,Map 和 Reduce, 这是一个令人惊讶的简单却又威力巨大的模型。适合用 MapReduce 来处理的数据集(或任务)有一个基本要求: 待处理的数据集可以分解成许多小的数据集,而且每一个小数据集都可以完全并行地进行处理
    这里写图片描述

            计算模型的核心是 Map 和 Reduce 两个函数,这两个函数由用户负责实现,功能是按一定的映射规则将输入的 <key, value> 对转换成另一个或一批 <key, value> 对输出。
    这里写图片描述
            以一个计算文本文件中每个单词出现的次数的程序为例,<k1,v1> 可以是 <行在文件中的偏移位置, 文件中的一行>,经 Map 函数映射之后,形成一批中间结果 <单词,出现次数>, 而 Reduce 函数则可以对中间结果进行处理,将相同单词的出现次数进行累加,得到每个单词的总的出现次数。
    基于 MapReduce 计算模型编写分布式并行程序非常简单,程序员的主要编码工作就是实现 Map 和 Reduce 函数,其它的并行编程中的种种复杂问题,如分布式存储,工作调度,负载平衡,容错处理,网络通信等,均由 MapReduce 框架(比如 Hadoop )负责处理,程序员完全不用操心。

    ##2.2 MapReduce框架
    ### 2.2.1运行架构图
    如下:这里写图片描述

    ### 2.2.流程分析
    1.在客户端启动一个作业。
    2.向JobTracker请求一个Job ID。
    3.将运行作业所需要的资源文件复制到HDFS上,包括MapReduce程序打包的JAR文件、配置文件和客户端计算所得的输入划分信息(输入划分信息?)。这些文件都存放在JobTracker专门为该作业创建的文件夹中。文件夹名为该作业的Job ID。JAR文件默认会有10个副本(mapred.submit.replication属性控制);输入划分信息告诉了JobTracker应该为这个作业启动多少个map任务等信息。
    4.JobTracker接收到作业后,将其放在一个作业队列里,等待作业调度器对其进行调度(这里是不是很像微机中的进程调度呢,呵呵),当作业调度器根据自己的调度算法调度到该作业时,**会根据输入划分信息为每个划分创建一个map任务,并将map任务分配给TaskTracker执行。对于map和reduce任务,TaskTracker根据主机核的数量和内存的大小有固定数量的map槽和reduce槽。**这里需要强调的是:map任务不是随随便便地分配给某个TaskTracker的,这里有个概念叫:数据本地化(Data-Local)。意思是:将map任务分配给含有该map处理的数据块的TaskTracker上,同时将程序JAR包复制到该TaskTracker上来运行,这叫“运算移动,数据不移动”。而分配reduce任务时并不考虑数据本地化。
    5.TaskTracker每隔一段时间会给JobTracker发送一个心跳,告诉JobTracker它依然在运行,同时心跳中还携带着很多的信息,比如当前map任务完成的进度等信息。当JobTracker收到作业的最后一个任务完成信息时,便把该作业设置成“成功”。当JobClient查询状态时,它将得知任务已完成,便显示一条消息给用户。
    以上是在客户端、JobTracker、TaskTracker的层次来分析MapReduce的工作原理的,下面我们再细致一点,从map任务和reduce任务的层次来分析分析吧。
    ### 2.2.2.Map、Reduce任务中Shuffle和排序的过程
    流程分析:
    这里写图片描述

    Map端:
            1.每个输入分片会让一个map任务来处理,默认情况下,以HDFS的一个块的大小(默认为64M)为一个分片,当然我们也可以设置块的大小。map输出的结果会暂且放在一个环形内存缓冲区中(该缓冲区的大小默认为100M,由io.sort.mb属性控制),当该缓冲区快要溢出时(默认为缓冲区大小的80%,由io.sort.spill.percent属性控制),会在本地文件系统中创建一个溢出文件,将该缓冲区中的数据写入这个文件。

            2.在写入磁盘之前,线程首先根据reduce任务的数目将数据划分为相同数目的分区,也就是一个reduce任务对应一个分区的数据。这样做是为了避免有些reduce任务分配到大量数据,而有些reduce任务却分到很少数据,甚至没有分到数据的尴尬局面。其实分区就是对数据进行hash的过程。然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行Combia操作,这样做的目的是让尽可能少的数据写入到磁盘。

            3.当map任务输出最后一个记录时,可能会有很多的溢出文件,这时需要将这些文件合并。合并的过程中会不断地进行排序和combia操作,目的有两个:1.尽量减少每次写入磁盘的数据量;2.尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,这里可以将数据压缩,只要将mapred.compress.map.out设置为true就可以了。

            4.将分区中的数据拷贝给相对应的reduce任务。有人可能会问:分区中的数据怎么知道它对应的reduce是哪个呢?其实map任务一直和其父TaskTracker保持联系,而TaskTracker又一直和JobTracker保持心跳。所以JobTracker中保存了整个集群中的宏观信息。只要reduce任务向JobTracker获取对应的map输出位置就ok了哦。

    到这里,map端就分析完了。那到底什么是Shuffle呢?Shuffle的中文意思是“洗牌”,如果我们这样看:一个map产生的数据,结果通过hash过程分区却分配给了不同的reduce任务,是不是一个对数据洗牌的过程呢?呵呵。

    Reduce端:
            1.Reduce会接收到不同map任务传来的数据,并且每个map传来的数据都是有序的。如果reduce端接受的数据量相当小,则直接存储在内存中(缓冲区大小由mapred.job.shuffle.input.buffer.percent属性控制,表示用作此用途的堆空间的百分比),如果数据量超过了该缓冲区大小的一定比例(由mapred.job.shuffle.merge.percent决定),则对数据合并后溢写到磁盘中。
            2.随着溢写文件的增多,后台线程会将它们合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。其实不管在map端还是reduce端,MapReduce都是反复地执行排序,合并操作,现在终于明白了有些人为什么会说:排序是hadoop的灵魂。
            3.合并的过程中会产生许多的中间文件(写入磁盘了),但MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数

    ##2.3 Hadoop简介
    ###2.3.1 Hadoop是什么
    MapReduce的一个开源实现
    ### 2.3.2数据分布存储
            Hadoop 中的分布式文件系统 HDFS 由一个管理结点 ( NameNode )和N个数据结点 ( DataNode )组成,每个结点均是一台普通的计算机。在使用上同我们熟悉的单机上的文件系统非常类似,一样可以建目录,创建,复制,删除文件,查看文件内容等。但其底层实现上是把文件切割成 Block,然后这些 Block 分散地存储于不同的 DataNode 上,每个 Block 还可以复制数份存储于不同的 DataNode 上,达到容错容灾之目的。NameNode 则是整个 HDFS 的核心,它通过维护一些数据结构,记录了每一个文件被切割成了多少个 Block,这些 Block 可以从哪些 DataNode 中获得,各个 DataNode 的状态等重要信息。
    ###2.3.3 分布式并行计算
            Hadoop 中有一个作为主控的 JobTracker,用于调度和管理其它的 TaskTracker, JobTracker 可以运行于集群中任一台计算机上。TaskTracker 负责执行任务,必须运行于 DataNode 上,即 DataNode 既是数据存储结点,也是计算结点。 JobTracker 将 Map 任务和 Reduce 任务分发给空闲的 TaskTracker, 让这些任务并行运行,并负责监控任务的运行情况。如果某一个 TaskTracker 出故障了,JobTracker 会将其负责的任务转交给另一个空闲的 TaskTracker 重新运行。
    ###2.3.4 本地计算
            数据存储在哪一台计算机上,就由这台计算机进行这部分数据的计算,这样可以减少数据在网络上的传输,降低对网络带宽的需求。在 Hadoop 这样的基于集群的分布式并行系统中,计算结点可以很方便地扩充,而因它所能够提供的计算能力近乎是无限的,但是由是数据需要在不同的计算机之间流动,故网络带宽变成了瓶颈,是非常宝贵的,“本地计算”是最有效的一种节约网络带宽的手段,业界把这形容为“移动计算比移动数据更经济”。

    这里写图片描述

    ###2.3.5 任务粒度

             把原始大数据集切割成小数据集时,通常让小数据集小于或等于 HDFS 中一个 Block 的大小(缺省是 64M),这样能够保证一个小数据集位于一台计算机上,便于本地计算。有 M 个小数据集待处理,就启动 M 个 Map 任务,注意这 M 个 Map 任务分布于 N 台计算机上并行运行,Reduce 任务的数量 R 则可由用户指定。
    ###2.3.6 Partition
            把 Map 任务输出的中间结果按 key 的范围划分成 R 份( R 是预先定义的 Reduce 任务的个数),划分时通常使用 hash 函数如: hash(key) mod R,这样可以保证某一段范围内的 key,一定是由一个 Reduce 任务来处理,可以简化 Reduce 的过程。
    ###2.3.7 Combine
            在 partition 之前,还可以对中间结果先做 combine,即将中间结果中有相同 key的 <key, value> 对合并成一对。combine 的过程与 Reduce 的过程类似,很多情况下就可以直接使用 Reduce 函数,但 combine 是作为 Map 任务的一部分,在执行完 Map 函数后紧接着执行的。Combine 能够减少中间结果中 <key, value> 对的数目,从而减少网络流量。

    ###2.3.8 Reduce 任务从 Map 任务结点取中间结果
            Map 任务的中间结果在做完 Combine 和 Partition 之后,以文件形式存于本地磁盘。中间结果文件的位置会通知主控 JobTracker, JobTracker 再通知 Reduce 任务到哪一个 DataNode 上去取中间结果。注意所有的 Map 任务产生中间结果均按其 Key 用同一个 Hash 函数划分成了 R 份,R 个 Reduce 任务各自负责一段 Key 区间。每个 Reduce 需要向许多个 Map 任务结点取得落在其负责的 Key 区间内的中间结果,然后执行 Reduce 函数,形成一个最终的结果文件。
    ###2.3.9 任务管道
            有 R 个 Reduce 任务,就会有 R 个最终结果,很多情况下这 R 个最终结果并不需要合并成一个最终结果。因为这 R 个最终结果又可以做为另一个计算任务的输入,开始另一个并行计算任务
    ###2.3.10

    ##2.4Hadoop基本类
    ###2.4. 1 InputFormat类
    该类的作用是将输入的文件和数据分割成许多小的split文件,并将split的每个行通过LineRecorderReader解析成<Key,Value>,通过job.setInputFromatClass()函数来设置,默认的情况为类TextInputFormat,其中Key默认为字符偏移量,value是该行的值。

    ###2.4.2.Map类
    根据输入的<Key,Value>对生成中间结果,默认的情况下使用Mapper类,该类将输入的<Key,Value>对原封不动的作为中间按结果输出,通过job.setMapperClass()实现。实现Map函数。

    ###2.4.3.Combine类
    实现combine函数,该类的主要功能是合并相同的key键,通过job.setCombinerClass()方法设置,默认为null,不合并中间结果。实现map函数

    ###2.4.4.Partitioner类
    该该主要在Shuffle过程中按照Key值将中间结果分成R份,其中每份都有一个Reduce去负责,可以通过job.setPartitionerClass()方法进行设置,默认的使用hashPartitioner类。实现getPartition函数
    ###2.4.5.Reducer类
    将中间结果合并,得到中间结果。通过job.setReduceCalss()方法进行设置,默认使用Reducer类,实现reduce方法。
    ###2.4. 6.OutPutFormat类
    该类负责输出结果的格式。可以通过job.setOutputFormatClass()方法进行设置。默认使用TextOUtputFormat类,得到<Key,value>对。

    hadoop主要是上面的六个类进行mapreduce操作,使用默认的类,处理的数据和文本的能力很有限,具体的项目中,用户通过改写这六个类(重载六个类),完成项目的需求。说实话,我刚开始学的时候,我怀疑过Mapreudce处理数据功能,随着学习深入,真的很钦佩mapreduce的设计,基本就二个函数,通过重载,可以完成所有你想完成的工作

    ##2.5Hadoop编程实例
    ###2.5.1 环境搭建
    Cygwin 安装配置

    1. 下载Cygwin安装文件
    2. 运行安装文件,选择一个下载站点,继续
    3. 选择要安装的程序,默认是不安装某些组件,需要手动选择
            Net Category下的:openssh,openssl
            BaseCategory下的:sed (若需要Eclipse,必须sed)
            Devel Category下的:subversion(建议安装)
    4. 等待下载并完成安装,之后,设置环境变量,把 C:/cygwin/bin;C:/cygwin/usr/bin 加入到系统环境变量的Path中
    5. 打开cygwin,输入 ssh-host-config
        当询问if privilege separation should be used 时输入 no . 
        当询问if sshd should be installed as a service 时输入yes . 
        当询问about the value of CYGWIN environment variable enter 时输入 ntsec .
        其余询问均输入 no
    ps:如果电脑上没有 有密码的帐号,配置会不成功。此时,应该创建一个windows 带密码的帐号,也可以通过该配置界面创建一个
    6. 打开 控制面板-》管理-》服务 启动名为 CYGWIN sshd 的服务,亦可在cygwin中输入 cygrunsrv --start sshd 启动sshd,
        输入cygrunsrv --stop sshd停止sshd
    7. 打开cygwin,输入 ssh-keygen,当询问要filenames 和 pass phrases 的时候都点回车,接受默认的值
    8. 命令结束后输入 cd ~/.ssh 转到.ssh目录,输入 ls –l 应该包含两个文件:id_rsa.pub 和 id_rsa
    9. 在第8步的窗口(当前目录在.ssh)中输入 cat id_rsa.pub >> authorized_keys
    10. 输入 ssh localhost 启动SSH
    

    PS:对于window64位系统,开始我安装的是对应的64位的Cygwin,但是配置不成功,会出现如下错误。删除后,重新安装32位的cygwin后,就好了
    这里写图片描述
    在cygwin中开启停用删除服务的命令:
    开启服务: $ net start 服务名
    停止服务: $ net stop 服务名
    删除服务: $ cygrunsrv -R 服务名
    cygwin自带的命令:
    检查所有安装的软件的版本号: $ cygcheck -c
    检查当前Cygwin的版本号: $ cygcheck -c cygwin
    cygwin编译搭建hadoop环境需要安装的软件包:
    1.openssh
    2.openssl
    3.sed
    4.zlib
    4.tcp_wrappers
    5.diffutils
    6.vim
    7.subversion
    cygwin没有自动卸载功能,需要手动操作3个步骤如下:
    1.停止服务: $ net stop 服务名
    2.删除服务: $ cygrunsrv -R 服务名
    3.删除cygwin文件

    伪分布模式配置
    可以把伪分布模式看作是只有一个节点的集群,在这个集群中,这个节点既是Master,也是Slave,既是NameNode,也是DataNode,既是JobTracker,也是TaskTracker
    这种模式也是在一台单机上运行,但用不同的 Java 进程模仿分布式运行中的各类结点 ( NameNode, DataNode, JobTracker, TaskTracker, Secondary NameNode ),请注意分布式运行中的这几个结点的区别:
    从分布式存储的角度来说,集群中的结点由一个 NameNode 和若干个 DataNode 组成, 另有一个 Secondary NameNode 作为 NameNode 的备份。 从分布式应用的角度来说,集群中的结点由一个 JobTracker 和若干个 TaskTracker 组成,JobTracker 负责任务的调度,TaskTracker 负责并行执行任务。TaskTracker 必须运行在 DataNode 上,这样便于数据的本地计算。JobTracker 和 NameNode 则无须在同一台机器上

    hadoop配置文件详解、安装及相关操作
    http://blog.csdn.net/lin_fs/article/details/7349497
    http://blog.csdn.net/ruby97/article/details/7423088
    注意事项:
    对于配置文件的更改,我开始是直接在window下打开修改的,结果出现如下错误:
    这里写图片描述
    原因:在windows下打开修改后,会更改文件的编码方式,使得文件在linux环境下读取错误问题
    解决办法:
    1.使用utraedit工具打开后,转换成Linux编码方式
    2.重新操作,在复制后,不在window下修改,直接在Linux中用vim编辑器打开修改(需要了解vim命令)
    改完之后,重新操作,结果如下:
    这里写图片描述

    关于错误:ipc.Client: Retrying connect to server: localhost/127.0.0.1:9000. Already tried 0 time(s).的错误。hadoop安装完成
    用jps命令,也看不不到namenode的进程, 必须再用命令hadoop namenode format格式化后,才能再使用
    原因是:hadoop默认配置是把一些tmp文件放在/tmp目录下,重启系统后,tmp目录下的东西被清除,所以报错
    解决方法:在conf/core-site.xml (0.19.2版本的为conf/hadoop-site.xml)中增加以下内容

       <property>
        <name>hadoop.tmp.dir</name>
        <value>/var/log/hadoop/tmp</value>
       <description>A base for other temporary directories</description>
       </property>
       重启hadoop后,格式化namenode即可 
    

    测试配置是否成功
    浏览器下查看Hadoop系统情况的地址。
    http://127.0.0.1:50070/ HDFS情况
    http://127.0.0.1:50060/ Task Tracker 情况
    http://127.0.0.1:50030/ Job Tracker-Map/Reduce Administration
    这里写图片描述

    ###2.5. 2 hadoop命令 1. 格式化工作空间 bin/hadoop namenode –format
    1. 启动hdfs
      进入hadoop目录,在bin/下面有很多启动脚本,可以根据自己的需要来启动。

    三、Hadoop hdfs 整合
    可按如下步骤删除和更改hdfs不需要的文件:
    1.将hadoop-core-1.0.0.jar 移动到lib目录下。
    2. 将ibexec目录下的文件移动到bin目录下。
    3. 删除除bin、lib、conf、logs之外的所有目录和文件。
    4. 如果需要修改日志存储路径,则需要在conf/hadoop-env.sh文件中增加:
    export HADOOP_LOG_DIR=/home/xxxx/xxxx即可。
    四、HDFS文件操作
    Hadoop使用的是HDFS,能够实现的功能和我们使用的磁盘系统类似。并且支持通配符,如*。

    1. 查看文件列表
      查看hdfs中/user/admin/hdfs目录下的文件:bin/hadoop fs -ls /user/admin/hdfs
      查看hdfs中/user/admin/hdfs目录下的所有文件(包括子目录下的文件):bin/hadoop fs -lsr /user/admin/hdfs

    2. 创建文件目录
      新建一个叫做newDir的新目录:bin/hadoop fs -mkdir /user/admin/hdfs/newDir

    3. 删除hdfs中/user/admin/hdfs目录下一个名叫needDelete的文件: bin/hadoop fs -rm /user/admin/hdfs/needDelete
      删除hdfs中/user/admin/hdfs目录以及该目录下的所有文件:bin/hadoop fs -rmr /user/admin/hdfs

    4. 上传文件
      上传一个本机/home/admin/newFile的文件到hdfs中/user/admin/hdfs目录下
      sh bin/hadoop fs –put /home/admin/newFile /user/admin/hdfs/

    5. 下载文件
      下载hdfs中/user/admin/hdfs目录下的newFile文件到本机/home/admin/newFile中
      执行sh bin/hadoop fs –get /user/admin/hdfs/newFile /home/admin/newFile

    6. 查看hdfs中/user/admin/hdfs目录下的newFile文件
      bin/hadoop fs –cat /home/admin/newFile

    7.学习各种 HDFS 命令的使用:bin/hadoop dfs –help 可以

    ###2.5. 3 运行 wordcount 应用
    1.将本地文件系统上的 ./test-in 目录拷到 HDFS 的根目录上,目录名改为 input
    $ bin/hadoop dfs -put test input

    2.查看执行结果,将文件从 HDFS 拷到本地文件系统中再查看:
    $ bin/hadoop jar hadoop-0.20.0-examples.jar wordcount input output
    $ bin/hadoop dfs -get output output
    $ cat output/*
    也可以直接查看
    $ bin/hadoop dfs -cat output/*
    $ bin/stop-all.sh #停止 hadoop 进程

    ###2.5.4 eclipse编程环境搭建
    http://www.cnblogs.com/flyoung2008/archive/2011/12/09/2281400.html

    展开全文
  • 我们通常说的分布式系统其实是分布式软件系统,即支持分布式处理的软件系统,它是在通信网络互联的多处理机体系结构上执行任务的,包括分布式操作系统、分布式程序设计语言及其编译(解释)系统、分布式文件系统和...

             我们通常说的分布式系统其实是分布式软件系统,即支持分布式处理的软件系统,它是在通信网络互联的多处理机体系结构上执行任务的,包括分布式操作系统、分布式程序设计语言及其编译(解释)系统、分布式文件系统和分布式数据库系统等。Hadoop是分布式软件系统中文件系统这一层的软件,它实现了分布式文件系统和部分分布式数据库的功能。Hadoop中的分布式文件系统HDFS能够实现数据在计算机集群组成的云上高效的存储和管理,Hadoop中的并行编程框架MapReduce能够让用户编写的Hadoop并行应用程序运行更加简化。下面简单介绍一下基于Hadoop进行分布式并发编程的相关知识:

      Hadoop上的并行应用程序开发是基于MapReduce编程框架的。MapReduce编程模型的原理是:利用一个输入的key/value 对集合来产生一个输出的key/value 对集合。MapReduce库的用户用两个函数来表达这个计算:Map和Reduce。

      用户自定义的map函数接收一个输入的key/value 对,然后产生一个中间key/value 对的集合。MapReduce把所有具有相同key值的value集合在一起,然后传递给reduce函数。

      用户自定义的reduce函数接收key和相关的value集合。reduce函数合并这些value值,形成一个较小的value集合。一般来说,每次reduce函数调用只产生0或1个输出的value值。通常我们通过一个迭代器把中间的value值提供给reduce 函数,这样就可以处理无法全部放入内存中的大量的value值集合了。

      下图是MapReduce的数据流图,这个过程简而言之就是将大数据集分解为成百上千个小数据集,每个(或若干个)数据集分别由集群中的一个节点(一般就是一台普通的计算机)进行处理并生成中间结果,然后这些中间结果又由大量的节点合并,形成最终结果。下图也指出了MapReduce框架下并行程序中的三个主要函数:map、reduce、main。在这个结构中,需要用户完成的工作仅仅是根据任务编写map和reduce两个函数。

    Hadoop与分布式开发
    ▲图 MapReduce的数据流图

      MapReduce计算模型非常适合在大量计算机组成的大规模集群上并行运行。上图中的每一个map 任务和每一个reduce 任务均可以同时运行于一个单独的计算节点上,可想而知,其运算效率是很高的,那么这样的并行计算是如何做到的呢?下面将简单介绍一下其原理。

      1.数据分布存储

      Hadoop分布式文件系统(HDFS)由一个名称节点(NameNode )和N个数据节点 (DataNode)组成,每个节点均是一台普通的计算机。在使用方式上HDFS与我们熟悉的单机文件系统非常类似,它可以创建目录,创建、复制和删除文件,以及查看文件的内容等。但HDFS底层把文件切割成了Block,然后这些 Block 分散地存储于不同的 DataNode 上,每个 Block 还可以复制数份数据存储于不同的 DataNode 上,达到容错容灾的目的。NameNode 则是整个 HDFS 的核心,它通过维护一些数据结构来记录每一个文件被切割成了多少个 Block、这些 Block 可以从哪些 DataNode 中获得,以及各个 DataNode 的状态等重要信息。

      2. 分布式并行计算

      Hadoop 中有一个作为主控的 JobTracker,用于调度和管理其他的 TaskTracker,JobTracker 可以运行于集群中的任意一台计算机上。TaskTracker则负责执行任务,它必须运行于 DataNode 上,也就是说DataNode 既是数据存储节点,也是计算节点。 JobTracker 将 map 任务和 reduce 任务分发给空闲的 TaskTracker,让这些任务并行运行,并负责监控任务的运行情况。如果某一个 TaskTracker 出了故障,JobTracker 会将其负责的任务转交给另一个空闲的 TaskTracker 重新运行。

      3. 本地计算

      数据存储在哪一台计算机上,就由哪台计算机进行这部分数据的计算,这样可以减少数据在网络上的传输,降低对网络带宽的需求。在 Hadoop 这类基于集群的分布式并行系统中,计算节点可以很方便地扩充,它所能够提供的计算能力近乎无限,但是由于数据需要在不同的计算机之间流动,故网络带宽变成了瓶颈,“本地计算”是一种最有效的节约网络带宽的手段,业界把这形容为“移动计算比移动数据更经济”。

      4. 任务粒度

      把原始大数据集切割成小数据集时,通常让小数据集小于或等于 HDFS 中一个 Block 的大小(默认是64MB),这样能够保证一个小数据集是位于一台计算机上的,便于本地计算。有 M 个小数据集待处理,就启动 M 个 map 任务,注意这 M 个map 任务分布于 N 台计算机上,它们会并行运行,reduce 任务的数量 R 则可由用户指定。

      5. 数据分割(Partition)

      把 map 任务输出的中间结果按 key 的范围划分成R份(R是预先定义的reduce 任务的个数),划分时通常使用 hash 函数(如:hash(key) mod R),这样可以保证某一范围内的 key一定是由一个 reduce 任务来处理的,可以简化 Reduce 的过程。

      6. 数据合并(Combine)

      在数据分割之前,还可以先对中间结果进行数据合并(Combine),即将中间结果中有相同 key的 对合并成一对。Combine 的过程与reduce 的过程类似,很多情况下可以直接使用reduce 函数,但 Combine 是作为map 任务的一部分,在执行完map函数后紧接着执行的。Combine 能够减少中间结果中 对的数目,从而降低网络流量。

      7. Reduce

      Map 任务的中间结果在做完 Combine 和 Partition 之后,以文件形式存于本地磁盘上。中间结果文件的位置会通知主控 JobTracker,JobTracker 再通知 reduce 任务到哪一个 DataNode 上去取中间结果。注意,所有的map 任务产生的中间结果均按其key 值用同一个 hash 函数划分成了R份,R个reduce 任务各自负责一段key 区间。每个reduce 需要向许多个map 任务节点取得落在其负责的key 区间内的中间结果,然后执行reduce函数,形成一个最终的结果文件。

      8. 任务管道

      有 R 个 reduce 任务,就会有 R 个最终结果,很多情况下这 R 个最终结果并不需要合并成一个最终结果,因为这 R 个最终结果又可以作为另一个计算任务的输入,开始另一个并行计算任务,这也就形成了任务管道。

          这里简要介绍了在并行编程方面Hadoop中MapReduce编程模型的原理、流程、程序结构和并行计算的实现,MapReduce程序的详细流程、编程接口、程序实例等将在后续文章中补上。

    展开全文
  • 并行编程设计模式

    千次阅读 2014-12-04 10:06:20
    这篇文章是对这段时间学习并行编程中的设计模式的一个总结。有不当之处,希望得到大家的批评、指正。 首先,所谓“并行编程中的设计模式”(patterns in parallel programming)仍处于不断的被发现、发掘的阶段。...
  • 并行编程中的设计模式

    千次阅读 2014-04-10 22:02:19
    这篇文章是对这段时间学习并行编程中的设计模式的一个总结。有不当之处,希望得到大家的批评、指正。 首先,所谓“并行编程中的设计模式”(patterns in parallel programming)仍处于不断的被发现、发掘的阶段。...
  • 19.1让一切“并行”——任务并行原理及应用 19.3.1 任务并行库简介  任务并行库(TPL:Task Parallel Library)是.NET 4.0为帮助软件工程师开发并行程序而提供的一组类,位于System.Threading和System....
  • c++ 并行编程

    万次阅读 2017-05-02 17:30:52
    本博客将看C++并行编程的例子 首先看如何看 #include #include using namespace std; int main() { clock_t startTime,endTime; startTime = clock(); for (int i = 0; i ; i++) { i++; }
  • Hadoop 是一个实现了 MapReduce 计算模型的开源分布式并行编程框架,借助于 Hadoop, 程序员可以轻松地编写分布式并行程序,将其运行于计算机集群上,完成海量数据的计算。在本文中,详细介绍了如何针对一个具体的...
  • 每周荐书:MyBatis、并行编程、Ansible(评论送书)

    万次阅读 热门讨论 2017-06-28 14:32:43
    每周荐书:MyBatis、并行编程、Ansible(评论送书) 感谢大家对每周荐书栏目的支持,先公布下上周中奖名单 u013045437 海马-赖人 可伸缩架构:面向增长应用的高可用   llld5553 FengGongFu Scratch...
  • 本文假设您已经了解一般并行编程知识,了解Java concurrent部分如ExecutorService等相关内容。 虽说是Java的ForkJoin并行框架,但不要太在意Java,其中的思想在其它语言环境也是同样适用的。因为并发编程在本质上是...
  • 步进电机工作原理模拟程序设计摘 要本次设计通过汇编程序,模拟混合两相步进电机工作原理。通过按键控制步进电机的启动、停止与电机工作方式的选择,并且在PC显示器上模拟显示电机按指定转速周而复始的转动。本程序...
  • MATLAB并行编程

    千次阅读 2015-10-08 10:26:29
    1 并行问题的由来——从抛硬币说起  举个简单的例子:抛100次硬币统计正面向上的次数。我们可以拿一个硬币重复地抛100次。但有人嫌麻烦,就想能不能再叫一个人带另外一个硬币过来,两个人同时抛,这样每个人就能...
  • Python 并行编程教程 | Lynda教程 中文字幕Python Parallel Programming Solutions课程ID: 604237时长: 4.0小时所属类别:Python学习使用Python的并行编程技术,并探索可以编写代码的多种方法,允许一次执行多个任务...
  • 并行程序设计 目前并行程序设计的状况是:①并行软件的发展落后于并行硬件;②和串行系统的应用软件相比,现今的并行系统应用软件甚少且不成熟;③并行软件的缺乏是发展并行计算的主要障碍;④而且这种状态仍在...
  • 用 Hadoop 进行分布式并行编程

    千次阅读 2012-10-09 21:16:46
    Hadoop 简介摘要:Hadoop 是一个实现了 MapReduce 计算模型的开源分布式并行编程框架,借助于 Hadoop, 程序员可以轻松地编写分布式并行程序,将其运行于计算机集群上,完成海量数据的计算。本文将介绍 MapReduce ...
  • linux 系统编程之-程序设计

    千次阅读 2019-06-24 18:16:10
    1.2.1 linux程序 (1)Linux应用程序表现为2种特殊类型的文件: A)可执行文件:计算机可以直接运行的文件。 B)脚本文件:一组指令的集合,这些指令将由另一个程序(解释器)来执行。 (2)登陆Linux系统时,与一...
  • 注意cudaMemcpyToSymbol函数的工作原理。该函数可以将数据复制到GPU上任何以全局符号命名的内存区域,无论该符号是全局内存还是常量内存。因此,我们可以将一块64K大小的数据块复制一个64K大小的内存区上,从而通过...
  • cuda并行编程基础(一)

    千次阅读 2017-12-19 00:03:00
    cuda能干啥,加速计算呗,学会了,对优化程序计算时间帮助大大的
  • 这篇文章来自公司的一封Q/A邮件。背景是想知道目前市面上的应用是否能在多核手机上性能有成倍增加。所以,自然而然就会问到一个基本问题,如何判断android中一个应用是否为多线程。...根据多核并行的知识,
  • OpenMP和MPI是并行编程

    千次阅读 2010-05-14 13:50:00
    OpenMP和MPI是并行编程的两个手段,对比如下:1. OpenMP:线程级(并行粒度);共享存储;隐式(数据分配方式);可扩展性差; 2. MPI:进程级;分布式存储;显式;可扩展性好。3. OpenMP采用共享存储,意味着它只...
  • OpenMP共享内存并行编程详解

    千次阅读 2014-07-02 15:35:11
    本文参考了wikipedia关于OpenMP条目、OpenMP.org(有OpenMP Specification)、MSDM上关于OpenMP条目以及教材《MPI与OpenMP并行程序设计(C语言版)》: http://zh.wikipedia.org/wiki/OpenMP ...
  • 简介 并行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个...目前流行的并行程序设计方法是,分布式内存结构上使用MPI,共享...
  • 程序设计语言 低级程序语言 特定的计算机系统所固有的语言 即:机器语言、汇编语言 特点:执行效率高、编制效率低 高级程序语言 与自然语言比较接近的语言 过程式语言:C, Pascal, Fortran, ADA 对象式语言:Java...
  • 周末,聊点轻松的话题。 本文通过一个不甚成功的优化自旋锁的半吊子尝试,聊一下操作系统并行的难点,中间的部分,...此外,代码可能不严谨,我个人编程能力有限,所以我可能只是表达想法,如果有编程高手能帮忙完...
  • OpenMP: OpenMP和MPI是并行编程

    千次阅读 2013-04-15 22:11:56
    OpenMP和MPI是并行编程的两个手段,对比如下:1. OpenMP:线程级(并行粒度);共享存储;隐式(数据分配方式);可扩展性差; 2. MPI:进程级;分布式存储;显式;可扩展性好。3. OpenMP采用共享存储,意味着它只...
  • 在Linux中用C语言进行OpenMP并行程序设计 ················································································...
  • 异步编程原理以及Java实现

    万次阅读 多人点赞 2019-03-30 14:16:11
    说实话多线程和异步是非常容易让人混淆的,好像产生的效果差不多,甚至有人称多线程为异步,实际上这两种技术背后的实现原理是不同的。 假设您有2个任务,不涉及任何IO(在多处理器机器上)。在这种情况下,线程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,812
精华内容 20,324
关键字:

并行编程原理及程序设计