MPI对道路车辆情况的Nagel-Schreckenberg 模型进行蒙特卡洛模拟

平台Ubuntu 16.04,Linux下MPI环境的安装见链接:https://blog.csdn.net/lusongno1/article/details/61709460

Nagel-Schreckenberg 模型,车辆的运动满足以下规则:

1.   假设当前速度是 v ,和前一辆车的距离为d。

2.   如果 d > v,它在下一秒的速度会提高到 v + 1 ,直到达到规定的最高限速。

3.   如果 d <= v,那么它在下一秒的速度会降低到 d - 1 。

4.   前三条完成后,司机还会以概率 p 随机减速1个单位,速度不会为负值。

5.   基于以上几点,车辆向前移动v(这里的v已经被更新)个单位。

实验规模:

  1. 车辆数量为100 000,模拟2000个周期后的道路情况。
  2. 车辆数量为 500 000 模拟 500个周期后的道路情况。
  3. 车辆数量为 1 000 000 ,模拟300个周期后的道路情况。

实验设计:

初始化条件:

所有车辆初速度为4,车辆间距为8,最大速度为8,最小速度为1,最后一辆车的位置是0。减速概率为0.3

车辆结构体:

typedef struct car{int v;int d;int p;
}car;

所有车辆为一个数组car_list

核心循环:

//更新距离
car_list[i].d=car_list[i+1].p-car_list[i].p;//依赖于前一辆车
//更新速度
if(car_list[i].d>car_list[i].v&& car_list[i].v<vmax)car_list[i].v++;//加速
if(car_list[i].d<=car_list[i].v)car_list[i].v=car_list[i].d-1;//减速
if(car_list[i].v>1 && rand()%10< p )car_list[i].v--;//随机减速
//更新位置
car_list[i].p+=car_list[i].v;

对这段程序进行周期次数的循环

并行设计:

在每个周期中,按照核心数(0…N-1)将车辆分为N个连续的区间,每个核心计算各自的部分。

i=(num_car/numprocs*myid);//指向这个集合的第一个元素

除第一个核心外其他的进程K都需要在更新自己的车辆部分之前发送第一辆车的位置到进程K-1,除最后一个进程外的其他进程K都要在计算自己部分的最后一辆车时接受进程K+1发送的位置数据以更新最后一辆车。

为避免标准通信方式导致后面的进程要等待前面的进程执行到最后开始接受的时候才执行完发送,采用缓存通信方式(MPI_Bsend)。

if(myid!=0){//如果不是第一个线程就要向前发送数据		MPI_Bsend(&(car_list[i].p),1,MPI_INT,myid-1,myid,MPI_COMM_WORLD);
}
//核心循环if(myid!=numprocs-1){//不是最后一个进程MPI_Recv(&(temp),1,MPI_INT,myid+1,myid+1,MPI_COMM_WORLD,&status);//更新距离car_list[i].d=temp-car_list[i].p;	
}

在周期结束之前要同步所有进程。

MPI_Barrier(MPI_COMM_WORLD);

输出结果:

只在四线程执行时输出到文件,将每个进程自己部分的车辆数据发送到第一个进程,第一个进程接收其它进程的数据整合后输出,并进行统计。

车辆的信息输出到result.txt中,格式为 进行输出的线程号 第几辆车:速度 位置 和前一辆车的距离

统计输出到statistic.txt中,前面输出的是速度统计,对应的速度有几辆车 。后面是位置统计,在位置范围有几辆车

结果分析:




可见不管哪种规模都会有大量的车处于速度为1的状态,随机减速会导致堵车情况。

运行时间分析:

10000

rank=0time:12.911823

rank=1time:12.937384

rank=2time:12.968312

rank=3time:12.837026

100000

rank=0time:127.054991

rank=1time:127.597898

rank=2time:127.428670

rank=3time:127.302298

 

rank=0time:169.043639

rank=1time:169.092520

rank=2time:169.038982

 

rank=0time:137.758731

rank=1time:137.782351

 

rank=0time:255.181992

500000

rank=0 time:158.620365

rank=1time:159.041463

rank=2time:158.827125

rank=3time:158.519957

 

rank=0time:211.242267

rank=1time:211.114535

rank=2time:211.117872

 

rank=0time:171.935731

rank=1time:171.970319

 

rank=0time:319.567614

 

1000000

rank=0 time:190.271859

rank=1time:190.056185

rank=2time:189.846401

rank=3time:190.314395

 

rank=0time:211.273677

rank=1time:211.328568

rank=2time:211.304030

 

rank=0time:172.247044

rank=1time:172.281147

 

rank=0time:318.965036

规模

时间/s

100k*2k

255

137

169

127

500k*0.5k

319

171

211

158

1000K*0.3k

318

172

211

190

加速比

100k*2k

1

1.861314

1.508876

2.007874

500k*0.5k

1

1.865497

1.511848

2.018987

1000K*0.3k

1

1.848837

1.507109

1.673684


实验遇到的问题:

1.如何串行执行

MPI的并行是进程的并行,所以MPI_Finalize()只是将资源释放了,并不是之后的程序就串行执行了,要想串行,可以指定一个进程执行。

2.结果输出

在用进程0输出所有车辆数据时发现只有线程0处理的部分数据有变更,其余数据维持在初始化时的状态。那么应该是每个进程是将处理了自己部分的数据的备份,而不是在原有数据的基础上处理的。所以要一个进程进行输出。

如果每个进程都自己输出数据就会产生文件写冲突而导致结果的不可预知,所以要将其它进程的数据发送到一个进程,用一个进程进行输出。

3.进程同步

如果进程间通信时设置的tag可以区分所有周期(比如设置为j*10+myid),那么在每个周期结束时就没有必要同步所有进程。

但是在这样修改之后运行时间没有什么区别,应该是核心的处理能力类似,同步产生的开销并不明显。

源程序:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>int num_car=100000;
int num_cycle[]={2000,500,300};const int v0=4,vmax=8,p=5;typedef struct car
{int v;int d;int p;
}car;
car car_list[1000000];int count[10]={0,0,0,0,0, 0,0,0,0,0};
int pos_count[20*8+10000*8]={0};//count per 100int main(int argc,char *argv[])
{//四线程写结果的时候打开文件FILE*fp = fopen("result_100000.txt","w");FILE*fp2 = fopen("statistic_100000.txt","w");//初始条件int i=0;for(i=0;i<num_car;i++){car_list[i].v=v0;car_list[i].p=vmax*i;car_list[i].d=vmax;}int     myid, numprocs;clock_t starttime,endtime;int    namelen;char   processor_name[MPI_MAX_PROCESSOR_NAME];MPI_Init(&argc,&argv);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);MPI_Comm_rank(MPI_COMM_WORLD,&myid);int* mpi_buffer=malloc(sizeof(int)*1000000);MPI_Buffer_attach(mpi_buffer,sizeof(int)*1000000);//模拟过程开始starttime=clock();int j=0;for(j=0;j<2000;j++){i=(num_car/numprocs*myid);//指向这个集合的第一个元素if(myid!=0)//如果不是第一个线程就要向前发送数据{			MPI_Bsend(&(car_list[i].p),1,MPI_INT,myid-1,j*10+myid,MPI_COMM_WORLD);}for(;i<num_car/numprocs*(myid+1)-1;i++){//更新距离car_list[i].d=car_list[i+1].p-car_list[i].p;//更新速度if(car_list[i].d>car_list[i].v && car_list[i].v<vmax)car_list[i].v++;if(car_list[i].d<=car_list[i].v)car_list[i].v=car_list[i].d-1;srand(i*num_car+j);if( car_list[i].v>1 ){int r=rand()%10;if(r<p){car_list[i].v--;//printf("#");}}//更新位置car_list[i].p+=car_list[i].v;}if(myid!=numprocs-1)//不是最后一个进程{int temp;MPI_Status status;MPI_Recv(&(temp),1,MPI_INT,myid+1,j*10+myid+1,MPI_COMM_WORLD,&status);//更新距离car_list[i].d=temp-car_list[i].p;	//printf("%d temp %d %d\n",myid,temp,car_list[i].d);}//更新速度if(car_list[i].v<vmax)car_list[i].v++;if(car_list[i].d<=car_list[i].v)car_list[i].v=car_list[i].d-1;srand((unsigned) time(NULL));if( car_list[i].v>1 && rand()%10< p ){car_list[i].v--;}//更新位置car_list[i].p+=car_list[i].v;//MPI_Barrier(MPI_COMM_WORLD);}//for cycle//模拟过程结束endtime=clock();printf("rank=%d time:%lf\n",myid,(double)(endtime-starttime)/CLOCKS_PER_SEC);//四线程的时候向文件写结果,别的线程时注释掉好了MPI_Barrier(MPI_COMM_WORLD);if(myid==0){MPI_Send((car_list),sizeof(car)*num_car/4,MPI_BYTE,3,myid,MPI_COMM_WORLD);	}if(myid==1){MPI_Send((car_list+num_car/4),sizeof(car)*num_car/4,MPI_BYTE,3,myid,MPI_COMM_WORLD);			}if(myid==2){MPI_Send((car_list+2*num_car/4),sizeof(car)*num_car/4,MPI_BYTE,3,myid,MPI_COMM_WORLD);			}if(myid==numprocs-1){MPI_Status status;MPI_Recv((car_list),sizeof(car)*num_car/4,MPI_BYTE,0,0,MPI_COMM_WORLD,&status);MPI_Recv((car_list+num_car/4),sizeof(car)*num_car/4,MPI_BYTE,1,1,MPI_COMM_WORLD,&status);MPI_Recv((car_list+2*num_car/4),sizeof(car)*num_car/4,MPI_BYTE,2,2,MPI_COMM_WORLD,&status);		int a;for(a=0;a<num_car;a++){fprintf(fp,"%d %d:%d %d %d\n",myid,a,car_list[a].v,car_list[a].p,car_list[a].d);}for(i=0;i<num_car;i++){count[car_list[i].v]++;pos_count[car_list[i].p/1000]++;}int k;for(k=0;k<10;k++){fprintf(fp2,"%d\t:%d\n",k,count[k]);}for(k=0;k<2*8+num_car*8/1000;k++){fprintf(fp2,"%d\t%d\n",k,pos_count[k]);}		}MPI_Barrier(MPI_COMM_WORLD);fclose(fp);fclose(fp2);MPI_Finalize();return 0;
}


转载于:https://www.cnblogs.com/biaoJM/p/10186706.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570818.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kerberos:cannot get master principle

The server encountered an internal error that prevented it from fulfilling this request 问题背景&#xff1a; 集群新增节点&#xff0c;添加datanode、hawq segment、pxf服务后&#xff0c;原先连接Hbase在hawq 外表报错“获取不到master principle 舍弃中……”、“Th…

BZOJ3223文艺平衡树——非旋转treap

此为平衡树系列第二道&#xff1a;文艺平衡树您需要写一种数据结构&#xff0c;来维护一个有序数列&#xff0c;其中需要提供以下操作&#xff1a; 翻转一个区间&#xff0c;例如原有序序列是5 4 3 2 1&#xff0c;翻转区间是[2,4]的话&#xff0c;结果是5 2 3 4 1 输入 第一行…

Linux centOS 硬盘分区挂载

文章转载自&#xff1a;http://linux008.blog.51cto.com/2837805/548711 1、什么是分区&#xff1f; 分区是将一个硬盘驱动器分成若干个逻辑驱动器&#xff0c;分区是把硬盘连续的区块当做一个独立的磁硬使用。分区表是一个硬盘分区的索引,分区的信息都会写进分区表。 2、为…

Ambari删除服务报错之CSRF protection is turned on

Ambari安装组件失败后执行 curl 删除服务报错 CSRF protection is turned on X-Requested_By HTTP Header is required 解决方案&#xff1a; vi /etc/ambari-server/conf/ambari-properties增加 api.csrfPrevention.enabledfalse重启Ambari: ambari-server restart重新执行s…

Android 中.aar文件生成方法与用法

https://i.cnblogs.com/EditPosts.aspx?opt1 无论是用Eclipse还是用Android Studio做android开发&#xff0c;都会接触到jar包&#xff0c;全称应该是&#xff1a;Java Archive&#xff0c;即java归档文件。在用AS的过程中&#xff0c;你会发现有aar这么个东西&#xff0c;经查…

Ambari实现HTTPS登陆

关于Ambari的安全、访问控制在这里有非常详细的介绍。 http://pivotalhd.docs.pivotal.io/docs/security-guide-ambari-2.1.2.html 另外还可以参考这一篇 https://community.hortonworks.com/articles/39865/enabling-https-for-ambariserver-and-troubleshootin.html Amba…

ffs, fls

linux内核中的宏ffs(x) linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __t (x); fls(__t & -__t); }) __t & -__t 等于找到__t 第一个为1的位(从低位开始),并把该位保留为1其余位清0. 例…

PLSQL注册码

Product Code: 4t46t6vydkvsxekkvf3fjnpzy5wbuhphqz serial Number: 601769 password: xs374ca

【JAVA学习】09.创建BootstrapTale列表页

【提要】只要JSON 返回了rows , total ,数据就会展示在列表 【步骤】 1、页面添加Table标签用于装载数据 <table class"table" id"userTable"> <tr><td>请输入查询条件查询</td></tr>   </table> 2、页面初始化请求…

安装ElasticSearch过程遇到的坑

采用默认安装时是可以成功安装的&#xff0c;但是只能在本机通过127.0.0.1:9200访问&#xff0c;修改: network.host: 为本机IP后&#xff0c;启动报错。 elasticsearch 5.3 安装过程中遇到了一些问题&#xff0c;这里简单记录一下 。 问题一&#xff1a;警告提示 [2016-11-…

JS的介绍

1.JS是什么 &#xff1f; JS是一门脚本语言&#xff0c;是一门解释性语言&#xff0c;是一种动态类型的语言&#xff0c;是一门基于对象的语言。 脚本语言和和编译语言的区别&#xff1a;脚本语言不需要编译&#xff0c;直接执行。编译语言是需要把代码翻译成计算机所认识的二进…

windows10上安装mysql

环境&#xff1a;windwos 10&#xff08;1511&#xff09; 64bit、mysql 5.7.14 一、下载mysql1. 在浏览器里打开mysql的官网http://www.mysql.com/2. 进入页面顶部的"Downloads"3. 打开页面底部的“Community(GPL) Downloads” 4. 在页面中间的位置找到我们windows上…

后台长期运行进程的三种方式

入门&#xff1a; nohup command > /var/log/test.log 2>&1 & 优雅&#xff1a; screen方式&#xff0c;通过screen 命令创建的环境下运行的终端命令&#xff0c;其父进程不是sshd 登陆会话&#xff0c;而是screen,这样就可以避免用户退出进程消失的问题&…

sql server 内存初探

sql server 内存初探 原文:sql server 内存初探一. 前言 对于sql server 这个产品来说&#xff0c;内存这块是最重要的一个资源&#xff0c; 当我们新建一个会话&#xff0c;相同的sql语句查询第二次查询时间往往会比第一次快&#xff0c;特别是在sql统计或大量查询数据输出时&…

hdfs查看目录大小文件大小

1、hadoop fs -du /test 查看test子目录大小 2、hadoop fs -count -q /test

使用TcpClient的例程

例子1&#xff1a; ///假定一切工作正常 ///连接后发送一次消息&#xff0c;然后不停接受消息并且打印 主要API说明 TcpClient clientnew TcpClient(); client.Connect("127.0.0.1",8888); NetworkStream streamclient.GetStream(); 发送&#xff1a; stream.Write(o…

Hawq超过最大允许连接数

Hawq默认master允许最大连接数250 segment最大连接数750 可以通过命令行或者Ambari更改连接数 1、 命令行 $ hawq config -c max_connections -v 1000 $ hawq config -c seg_max_connections -v 2000 $ hawq config -c max_prepared_transactions -v 1000 更改完成后&…

Mac原生解决ntfs格式只能读不能写

如何打开Mac OSX原生的读写NTFS功能&#xff08;支持OS X EI&#xff0c;秒杀NTFS&#xff09; 最近OS X EI更新成风&#xff0c;本人的是2014年初的macbookair&#xff0c;双系统&#xff0c;OSWIN&#xff08;仅仅用于工作需要的2个软件&#xff0c;装个bootcamp双系统稳定扎…

web api 权限控制

https://www.cnblogs.com/landeanfen/p/5287064.html 我只是个搬运工&#xff0c; 我只想存个档转载于:https://www.cnblogs.com/LoveAndPeace/p/9105037.html

Hadoop 跨集群复制文件

hadoop distcp -pbc hdfs://namenode1/test hdfs://namenode2/test 如果报用户权限写入被拒绝&#xff0c;切换到hdfs