前段时间学习了基于cloudSIM下云任务调度算法。这里我总结了一下贪心算法
-------代码部分来源于网络。里面加了一些自己的理解
首先我们需要了解贪心算法的工作机理:
- 贪心算法将一组云任务分配给一组虚拟机,使总执行时间接近最短。
- 矩阵time[i][j]表示云任务i在虚拟机j上所需的执行时间。
- 首先将云任务按其长度(MI)降序排列,虚拟机按其处理能力(MIPS)升序排列。
- 从矩阵中行号为0的任务(任务长度最大)开始,将其分配给最后一列对应的虚拟机(处理能力最强)。
- 如果该选择相对于其它选择是最优的负载尽量均衡,将云任务分配到执行时间最短的虚拟机上。
******需要注意的一点是当一个云任务分配给对应的虚拟机之后,如何后面的云任务需要在此虚拟机上执行,则其需要经历一个等待时间。
下面配图进行详细讲解:
注意:核心是在每一行中找到一个最小值。
在这里先假设有五台虚拟机 六个云任务,首先我们将一号云任务分配给五号虚拟机(云任务最长的分配给虚拟机处理能力最强的),之后我们将对二号云任务进行分配,由于此时4号虚拟机尚未分配云任务 因此,其最佳分配只会在4号及五号之间选择,值得注意的是这时 二号云任务在五号虚拟机上执行的时间还需要加上一号云任务在五号虚拟机上的执行时间(即它要执行所需要的等待时间,在四号虚拟机上由于此时未分配云任务,此时其需要等待的时间为0),以此类推,每一个云任务的分配都会对其后在该云任务对应的虚拟机上的云任务的执行时间产生影响。
下面大家可以结合代码进行理解:
public void bindCloudletsToVmsSimple2(){ //贪心算法
int cloudletNum=cloudletList.size();
System.out.println("云任务列表的数量"+cloudletNum);
int vmNum=vmList.size();
//time[i][j] 表示任务i在虚拟机j上的执行时间
double[][] time=new double[cloudletNum][vmNum];
//cloudletList按MI降序排列, vm按MIPS升序排列 MI 表示云任务的长度
Collections.sort(cloudletList,new Comparator<Cloudlet>(){
public int compare(Cloudlet o1, Cloudlet o2) {
return (int)(o2.getCloudletLength()-o1.getCloudletLength());
}
});
Collections.sort(vmList,new Comparator<Vm>(){
public int compare(Vm o1, Vm o2) {
return (int)(o1.getMips()-o2.getMips());
}
});
//For test//
System.out.println("///For test///");
for(int i=0;i<cloudletNum;i++){
System.out.print(cloudletList.get(i).getCloudletId()+":"+cloudletList.get
(i).getCloudletLength()+" ");
}
System.out.println();
for(int i=0;i<vmNum;i++){
System.out.print(vmList.get(i).getId()+":"+vmList.get(i).getMips()+" ");
}
System.out.println();
System.out.println("//");
//
for(int i=0;i<cloudletNum;i++){
for(int j=0;j<vmNum;j++){
time[i][j]=
(double)cloudletList.get(i).getCloudletLength()/vmList.get(j).getMips();
System.out.print("time["+i+"]["+j+"]="+time[i][j]+" ");
//For test
}
System.out.println(); //For test
}
double[] vmLoad=new double[vmNum];//在某个虚拟机上任务的总执行时间
int[] vmTasks=new int[vmNum]; //在某个Vm上运行的任务数量
double minLoad=0;//记录当前任务分配方式的最优值
int idx=0;//记录当前任务最优分配方式对应的虚拟机列号
//第一个cloudlet分配给最快的vm
vmLoad[vmNum-1]=time[0][vmNum-1]; //vmload表示某个虚拟机上任务的总执行时间
vmTasks[vmNum-1]=1;
cloudletList.get(0).setVmId(vmList.get(vmNum-1).getId());
// 外层循环用来分配云任务 内层循环给云任务配置合适的虚拟机//vmload表示某个虚拟机上任务的总执行时间
for(int i=1;i<cloudletNum;i++){ //minload 记录当前任务分配方式的最优值 i表示云任务编号
minLoad=vmLoad[vmNum-1]+time[i][vmNum-1];
idx=vmNum-1; //先将其与第一台虚拟机联系
for(int j=vmNum-2;j>=0;j--){
//如果当前虚拟机未分配任务,则比较完当前任务分配给该虚拟机是否最优
if(vmLoad[j]==0){ //虚拟机排序由快到慢 正好可以使云任务分配更加的合理化
if(minLoad>=time[i][j]+0)idx=j; //注意 整个程序的目的是让时间最小化 minload表示的是当前程序执行所需要的最小时间
break;
}
if(minLoad>vmLoad[j]+time[i][j]){
minLoad=vmLoad[j]+time[i][j]; //使整个程序最大合理化 重复比较
idx=j;
}
//简单的负载均衡
else if(minLoad==vmLoad[j]+time[i][j]&&vmTasks[j]<vmTasks[idx]) //使所有的虚拟机上分配的云任务尽可能的均衡
idx=j;
}
vmLoad[idx]+=time[i][idx];
vmTasks[idx]++;
cloudletList.get(i).setVmId(vmList.get(idx).getId());
System.out.print(i+"th "+"vmLoad["+idx+"]="+vmLoad[idx]+"minLoad="+minLoad);
System.out.println();
}
}
最后:这是我写的第一篇文章,经验可能不足,如果有什么不合理或者错误的地方,希望大家多多指教。谢谢