平台Ubuntu 16.04,Linux下MPI环境的安装见链接:https://blog.youkuaiyun.com/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已经被更新)个单位。
实验规模:
- 车辆数量为100 000,模拟2000个周期后的道路情况。
- 车辆数量为 500 000 模拟 500个周期后的道路情况。
- 车辆数量为 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);