并行与分布式计算期末复习提纲

并行与分布式计算

MPI

初始化

MPI_Init(&argc, &argv)

结束

MPI_Finalize()

MPI_COMM_WORLD

一个通信域,包含通信的所有进程

当前进程标识

MPI_Comm_rank(MPI_COMM_WORLD, &node);

通信域包含的进程数

MPI_Comm_size(MPI_COMM_WORLD, &size);

信息发送

MPI_Send(message, strlen(message), MPI_CHAR, 1, 99, MPI_COMM_WORLD);

1是目的进程标识

信息接收

MPI_Recv(message, strlen(message), MPI_CHAR, 0, 99, MPI_COMM_WORLD);

0是发送进程标识

#include"mpi.h"
int main(int argc, char **argv){
	char message[20];
    int myrank;
    MPI_Init(&argc,&argv); // 要传地址
    MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
    if(myrank == 0){
        strcy(message,"Hello, process 1");
		MPI_Send(message, strlen(message), MPI_CHAR, 1, 99, MPI_COMM_WORLD);
    }
    else if(myrank == 1){
        MPI_Recv(message, strlen(message), MPI_CHAR, 0, 99, MPI_COMM_WORLD);
        printf("messge: %s",message);
    }
    MPI_Finalize();
}

错误退出

master(0或者最后一个)进程退出,其他进程堵塞

#include"mpi.h"
#include<stdio.h>
int main(int argc, char **argv){
    int node, size,i;
   	int masternode = 0;
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&node);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    for(i=1;i<argc;++i){
		fprintf(stderr,"myid=%d, procs=%d, argv[%d]=%s\n",node,size,i,argv[i]);
        if(argv[i]&&strcmp("lastmaster",argv[i])==0){//字符串相等
			masternode=size-1;
        }
    }
    if(node == masternode){
        fprintf(stderr,"myid=%d is masternode Abort!\n",node);
        MPI_Abort(MPI_COMM_WORLD,99);
    }
    else{
		fprintf(stderr,"myid=%d is not masternode Barrier!\n",node);
        MPI_Barrier(MPI_COMM_WORLD);
    }
    MPI_Finalize();
}

数据接力传送

#include"mpi.h"
#include<stdio.h>
int main(int argc, char **argv){
    int rank, size, value;
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    do{
		if(rank==0){
			fprintf(stderr,"\nPlease give new value=");
            scanf("%d",&value);
            fprintf(stderr,"%d  read <-<- (%d)\n",rank,value);
            if(size>1){//进程数大于1
				MPI_Send(&value,1,MPI_INT,rank+1,0,MPI_COMM_WORLD);
                fprintf(stderr,"%d send (%d) ->-> %d\n",rank,value,rank+1);
            }
        }
        else{
            MPI_Recv(&value, 1, MPI_INT, rank-1,0, MPI_COMM_WORLD,&status);
            fprintf(stderr,"%d receive(%d) <-<- %d\n",rank,value,rank-1);
            if(rank<size-1){
                MPI_Send(&value,1,MPI_INT,rank+1,0,MPI_COMM_WORLD);
                fprintf(stderr,"%d send (%d)->-> %d\n",rank,value,rank+1);
            }
        }
        MPI_Barrier(MPI_COMM_WORLD);//执行一下同步,让所有进程执行完,使前后两次输入数据分隔开
    }while(value>=0);
    MPI_Finalize();
}

进程之间相互问候

#include"mpi.h"
#include<stdio.h>
#include<stdlib.h>
void Hello(void);
int main(int argc, char **argv){
    int rank, option, namelen, size;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    if(size<2){
		fprintf(stderr,"systest requires at least 2 processes");
        MPI_Abort(MPI_COMM_WORLD,1);
    }
    MPI_Get_processor_name(processor_name,&namelen);
    fpritnf(stderr,"Process %d is alive on %s\n",rank,processor_name);
    MPI_Barrier(MPI_COMM_WORLD);
    Hello();
    MPI_Finalize();
}

void Hello(void){
    int size, rank;
    int type = 1;
    int buffer[2], node;
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    if(rank==0){ //0进程负责打印提示消息
		printf("\nHello test from all to all\n");
        fflush(stdout);
    }
    for(node=0; node<size; node++){
		if(node!=rank){
			buffer[0]=rank;//自身标识
            buffer[1]=node;//被问候标识
            MPI_Send(buffer,2,MPI_INT,node,type,MPI_COMM_WORLD);
            MPI_Recv(buffer,2,MPI_INT,node,type,MPI_COMM_WORLD,&status);
            if((buffer[0]!=rank)||(buffer[1]!=node)){
                //不是问候自己的或者不是不是以被问候的身份问候自己
                (void) fprintf(stderr, "Hello: %d!=%d or %d!=%d\n",buffer[0],node,buffer[1],rank);
                printf("Mismatch on hello process ids; node = %d\n",node);
            }
         	printf("Hello form %d to %d\n",rank,node);
            fflush(stdout);
        }
    }
}

任意源和任意标识的使用

#include"mpi.h"
#include<stdio.h>
int main(int argc, char **argv){
    int rank, size, buff[1];
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    if(rank==0){
		for(int i=0;i<100*(size-1);++i){
			MPI_Recv(buf,1,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
            printf("Msg=%d from %d with tag%d\n",buf[0],status.MPI_SOURCE,status.MPI_TAG);
        }
    }
    else{
        for(int i=0;i<100;++i){
            buf[0]=rank+i;
            MPI_Send(buf,1,MPI_INT,0,i,MPI_COMM_WORLD);
        }
    }
    MPI_Finalize();
}

第9章 不同通信模式

通信模式 发送 接收
标准通信 MPI_Send MPI_Recv
缓存通信 MPI_Bsend
同步通信 MPI_Ssend
就绪通信 MPI_Rsend

使用同步消息发送,发送进程分别以同步方式发送1个和4个数据,消息标识tag分别为1和2,接收进程用标准接收操作接收,并检查收到数据的个数

#include"mpi.h"
#include<stdio.h>
#define SIZE 10
static int src = 0, dest = 1;//源进程,目的进程
int main(int argc, char **argv){
    int rank,size;
    int flag,rval,i;
    int act_size = 0;
    int buffer[SIZE];
    MPI_STATUS status, status1, status2;
    int count1, count2;
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    if(size!=2){
		fprintf(stderr,"*** This program uses exactly 2 processes! ***\n");
        MPI_Abort(MPI_COMM_WORLD,1);
    }
    act_size = 5; // 最大消息长度
    if(rank == src){ // 当前进程为发送进程
        act_size = 1;
        MPI_Ssend(buffer, act_size, MPI_INT, dest, 1, MPI_COMM_WORLD);
        fprintf(stderr,"MPI_Ssend %d data, tag = 1\n",act_size);
        act_size = 4;
    	MPI_Ssend(buffer, act_size, MPI_INT, dest, 2, MPI_COMM_WORLD);
        fprintf(stderr,"MPI_Ssend %d data, tag = 2\n",act_size);
    }
    else if(rank == dest){
		MPI_Recv(buffer, act_size, MPI_INT, src, 1, MPI_COMM_WORLD, &status1);
        MPI_Recv(buffer, act_size, MPI_INT, src, 2, MPI_COMM_WORLD, &status2);
        // act_size 是最大消息长度
        MPI_Get_count(&status1, MPI_INT, &count1);
        fprintf(stderr,"receive %d data, tag = %d\n",count1,status1.MPI_TAG);
        MPI_Get_count(&status2, MPI_INT, &count2);
        fprintf(stderr,"receive %d data, tag = %d\n",count2,status2.MPI_TAG);
    }
    MPI_Finalize();
}

第13章 组通信MPI程序设计

广播

MPI_Bcast(&value, 1, MPI_INT, 0,  MPI_COMM_WORLD);
#include<stdio.h>
#include"mpi.h"
int main(int argc, char **argv){
    int rank, value;
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    do{
		if(rank==0){
			scanf("%d",&value);
        }
        MPI_Bcast(&value,1,MPI_INT,0,MPI_COMM_WORLD);
        //如果当前是广播进程就发送,如果不是就接收,根据进程标识Bcast自动处理
        printf("Process %d got %d\n",rank,value);
    }while(value>=0); // 所有进程共用value
    MPI_Finalize();
}

收集

MPI_Gather(sendarray,100,MPI_INT,rbuf,rcounts,displs,MPI_INT,root,MPI_COMM_WORLD);
// rbuf 整型数组,接收消息缓存区起始地址
// rcounts 整型数组,每个进程接收的数据个数
// displs 整型数组,每个入口相对于rbuf的偏移
// root 接收进程的标识号

注意为数组开辟空间

收集和散发都是对应位置的缓存区数据交流

散发

MPI_Scatter(sendarray,100,MPI_INT,rbuf,100,MPI_INT,root,MPI_COMM_WORLD);
// root 发送进程的标识号

组收集

MPI_Allgather(sendarray,100,MPI_INT,rbuf,100,MPI_INT,MPI_COMM_WORLD);

第17章 共享存储编程

使程序并行化

double area, pi,x;
int i, n;

area = 0.0;
#program omp parallel for private(x)
for (i = 0; i < n; ++i){
    x = (i+0.5)/n;
    #pragma omp critical // 生成一个代码临界区,使执行该段代码的线程互斥
    area += 4.0/(1.0 + x*x);
}
pi = area / n;

归约操作

//归约操作
// 负责将部分和存储到私有变量中并在循环结束时将各个部分和相加等具体的操作
reduction(<op>:<variable>)
area = 0.0;
#pragma opm parallel for private(x) reduction(+:area)
for(i=0;i<n;++i){
    x = (i+0.5)/n;
    area += 4.0 / (1.0 + x*x);
}
pi = area / n;

名词解释

并行计算

并行计算是相对于串行计算来说的,可分为时间上的并行和空间上的并行。时间上的并行指的就是流水线技术,而空间上的并行则是指用多个处理器并发的执行计算。并行计算的目的就是提供单处理器无法提供的性能,使用多处理器求解单个问题。

分布式计算

分布式计算研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配个许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果。

并行计算机

并行计算机即能在同一时间执行多条指令或处理多个数据的计算机,并行计算机是并行计算的物理载体。

什么是MPI

  • MPI是一个库,而不是一门语言
  • MPI是一种标准或规范的代表,而不特指某一个对它的具体实现
  • MPI是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准

Hadoop

Hadoop是Apache软件基金会旗下的一个开源分布式计算平台,为用户提供了系统底层细节透明的分布式基础框架

Hadoop的核心是HDFS和MapReduce,HDFS为海量的数据提供了存储,而MapReduce为海量的数据提供了计算。

分布式文件系统&计算机集群

分布式文件系统把文件分布存储到多个计算机节点上,成千上万的计算机节点构成计算机集群。

HDFS

Hadoop Distributed File System

Hadoop 分布式文件系统,是指被设计成适合运行在通用硬件上的分布式文件系统

  • 兼容廉价的硬件设备
  • 流数据读写
  • 超大数据集
  • 简单的文件模型
  • 强大的跨平台兼容性

HDFS只设置了一个名称节点(主节点)

数据节点

数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并向名称节点定期发送自己所存储的块的列表。

每个数据节点中的数据会被保存在各自节点的本地linux文件系统中。

BigTable

Bigtable是一个分布式存储系统,起初用于解决典型的互联网搜索问题。

HBase

HBase是一个高可靠、高性能、面向列、可伸缩的分布式数据库,是谷歌BigTable的开源实现,主要用来存储非结构化和半结构化的松散数据,HBase的目标是处理非常庞大的表,可以通过水平扩展的方式,利用连接计算机集群处理有超过10亿行数据和数百万列元素组成的数据表。

Zookeeper

Zookeeper是一个分布式的,开发码源的分布式应用程序协调服务,是Hadoop和HBase的重要组件。

摩尔定律

CPU性能大约每隔18个月翻一番

从2005年开始摩尔定律逐渐失效

MapReduce

一种编程模型,将复杂的,运行与大规模集群上的并行计算过程高度地抽象到了两个函数:Map(映射)和Reduce(归约)。

采用分治的思想,让“计算向数据靠拢”,而不是“数据向计算靠拢”(挪动数据需要大量网络开销)

简答题

解决节点运行期间EditLog不断变大的问题

第二名称节点是HDFS架构中的一个重要组成部分,他是用来保存名称节点中对HDFS元数据信息的备份,并减少名称节点重启的时间。一般单独运行在一台机器上。

HDFS体系结构的局限性

  1. 命名空间的局限
  2. 性能的瓶颈
  3. 隔离问题
  4. 集群的可用性:一旦名称节点发生故障,整个集群不可用

Hadoop已经有HDFS和MapReduce,为什么需要HBase

Hadoop可以很好地解决大规模数据的离线批量处理问题,但是受限于Hadoop MapReduce编程框架的高延迟数据初级机制,是得Hadoop无法满足大规模数据试试处理应用的需求。

HBase和传统关系型数据库的比较

  1. 数据类型: HBase使用更简单的数据模型,它把数据存储为未经解释的字符串
  2. 数据操作:HBase在设计上就避免了复杂度表和表的关系,因此操作简单
  3. 存储模式:关系型数据库基于行存储,HBase基于列存储,每个列族都由几个文件保存,不同列族的文件是分离的
  4. 数据索引:关系型数据库可以针对不同列构建复杂的多个索引,以提高数据访问性能、HBase只有行键一个索引,使得整个系统很快。
  5. 数据维护:在关系数据库中,更新操作为替换操作,旧值从此消失。而HBase不会删除原来的版本,而是产生新版本。
  6. 可伸缩性:关系型数据库很难实现扩展,HBase就是为了灵活的水平扩展而开发的,能够轻易地通过在集群中增加或者减少硬件数量实现性能的伸缩。

MapReduce相较于传统的并行计算框架有什么优势

传统并行计算框架 MapReduce
集群架构/容错性 共享式(共享内存/共享存储),容错性差 非共享式,容错性好
硬件/价格/扩展性 刀片服务器、高速网、SAN,价格贵,扩展性差 普通PC机,便宜,扩展性好
编程/学习难度 what-how,难 what,简单
适用场景 实时、细粒度计算、计算密集型 批处理、非实时、数据密集型
发布了54 篇原创文章 · 获赞 46 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_40422121/article/details/103812411