二、coudBalance 资源分配案例

文章描述了一个如何通过Java编程模型,利用Jackson库和Lombok框架,结合ConstraintStream和Easy求解器,为具有不同配置的N个进程在N台电脑间分配任务,以最小化维护成本并满足CPU和内存资源限制的问题。
摘要由CSDN通过智能技术生成

这是一个官方的例子:假设现在有N个进程需要N台电脑去维护,且每台电脑配置可能不一样。每台电脑不管维护多少进程,他们的维护费用一致;进程所需的CPU功率之和与所需内存之和不能超过电脑的CPU功率与内存容量。求怎样分配能够降低维护成本。

图片示例:

一、开始建模。

jar包

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.15.2</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.15.2</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.15.2</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.4</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.5</version>
    </dependency>
①、资源对象
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 14:14
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public class Computer extends AbstractPersistable {

    /**
     * cpu功率
     */
    private Integer cpuPower;

    /**
     * 内存容量
     */
    private Integer memoryCapacity;

    /**
     * 网络容量
     */
    private Integer networkCapacity;

    /**
     * 维护费用
     */
    private Integer cost;

}
②、问题解决对象(包含资源对象)
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 14:22
 */
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@PlanningEntity
public class Processes extends AbstractPersistable {

    /**
     * 该进程需要的cpu
     */
    private Integer cpu;

    /**
     * 该进程需要的内存
     */
    private Integer ram;


    @PlanningVariable(valueRangeProviderRefs = {"computerRange"})
    private Computer computer;
}
③、规划类
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 14:32
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@PlanningSolution
@SuperBuilder
public class CouldBalancePlan extends AbstractPersistable {

    /**
     * 分值
     */
    @PlanningScore
    public HardSoftScore score;

    /**
     * 资源类、问题解决类(进程类)集合
     */
    @PlanningEntityCollectionProperty
    private List<Processes> processesList;

    /**
     * 资源类(电脑类)集合
     */
    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "computerRange")
    private List<Computer> computerList;

}

建模方式并不唯一,另一种方式我会在接下来的案例中给出

二、约束建立

本例中我们可以得到两个硬约束,一个软约束;硬约束不可被打破,软约束尽量不要打破。

①、硬约束:

1、进程所需CPU功率之和不能超过电脑的CPU功率;

2、进程所需的内存之和不能超过电脑的内存容量。

②、软约束:

每台电脑不管维护多少个进程,他的维护费用都是一致的,尽量节省维护成本。

三、求解器
①、ConstraintStream求解器:
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 14:39
 */
public class CouldBalanceConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                cpuConflict(constraintFactory),
                ramConflict(constraintFactory),
                costConflict(constraintFactory)
        };
    }

    /*****************************************************硬约束*********************************************************************/

    private Constraint cpuConflict(ConstraintFactory constraintFactory) {
        //接下来的代码有点类似于Stream流
        return constraintFactory
                //创建流
                .from(Processes.class)
                //进行分组
                .groupBy(Processes::getComputer, ConstraintCollectors.sum(Processes::getCpu))
                //过滤出不满足电脑CPU>进程CPU之和的情况
                .filter((c, sumCpu) -> c.getCpuPower() < sumCpu)
                //进行扣分;关闭流
                .penalize("Cpu conflict", HardSoftScore.ONE_HARD);
    }

    private Constraint ramConflict(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Processes.class)
                //进行分组
                .groupBy(Processes::getComputer, ConstraintCollectors.sum(Processes::getRam))
                //过滤出不满足电脑内存>进程内存之和的情况
                .filter((c, sumRam) -> c.getMemoryCapacity() < sumRam)
                //进行扣分
                .penalize("Ram conflict", HardSoftScore.ONE_HARD);
    }


    /*****************************************************软约束****************************************************************************/
    private Constraint costConflict(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Processes.class)
                //分组
                .groupBy(Processes::getComputer)
                //去重
                .distinct()
                //扣分
                .penalize("Cost Conflict", HardSoftScore.ONE_SOFT);

    }
}
②、Easy求解器
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 14:42
 */
public class CouldBalanceEasyScoreCalculator implements EasyScoreCalculator<CouldBalancePlan,
        HardSoftScore> {
    @Override
    public HardSoftScore calculateScore(CouldBalancePlan couldBalancePlan) {
        //硬约束分值
        int hardScore = 0;
        //软约束分值
        int softScore = 0;

        //这种写法带有局限性,
        // 当一台电脑能包揽所有进程的时候显得 不够贪婪(可能是本人太菜,思考不出合理的逻辑),
        // 后期不考虑使用,在这里只是给大家演示约束的逻辑

        List<Processes> list = couldBalancePlan.getProcessesList();
        //硬约束计算:只计算了CPU和内存
        for (Processes a : list) {
            for (Processes b : list) {
                if (!a.getId().equals(b.getId())) {
                    if (ObjectUtil.isNotNull(a.getComputer()) && ObjectUtil.isNotNull(b.getComputer())) {
                        if (a.getComputer().equals(b.getComputer())) {
                            int cpu = a.getCpu() + b.getCpu();
                            int ram = a.getRam() + b.getRam();

                            if (cpu > a.getComputer().getCpuPower() || ram > b.getComputer().getMemoryCapacity()) {
                                //如果进程的CPU之和大于电脑的CPU或者进程的内存之后大于电脑的内存
                                hardScore--;
                            }

                            if (cpu == a.getComputer().getCpuPower() && ram == a.getComputer().getMemoryCapacity()) {
                                //如果进程的CPU之和等于电脑的CPU并且进程的内存之和等于电脑的内存
                                hardScore++;
                            }
                        }
                    }
                }
            }
        }

        //软约束:想要把成本降到最低(每台电脑,不管维护多少个进程,它的维护费用都是一样的)
        List<Computer> collect = list.stream().map(Processes::getComputer).filter(ObjectUtil::isNotNull).distinct().collect(Collectors.toList());
        softScore = softScore - collect.size();


        return HardSoftScore.of(hardScore, softScore);
    }
}

这里的Easy求解器有一个问题,当一台电脑能包揽所有进程的时候最终结果还是两台电脑。原因是因为for循环的问题。解决方案可以自行探究,欢迎大家评论。

四、求解
/**
 * @author Xiao Mi feng
 * Created with IntelliJ IDEA
 * @date 2024-01-26 15:16
 */
public class CouldBalanceApp {

    public static void main(String[] args) throws JsonProcessingException {
        SolverFactory<CouldBalancePlan> objectSolverFactory = SolverFactory.create(new SolverConfig()
                .withSolutionClass(CouldBalancePlan.class)
                .withEntityClasses(Processes.class)
                .withConstraintProviderClass(
                        CouldBalanceConstraintProvider.class)
                .withTerminationSpentLimit(Duration.ofSeconds(10))
        );

        CouldBalancePlan couldBalancePlan = generateDemoData();

        CouldBalancePlan solve = objectSolverFactory.buildSolver().solve(couldBalancePlan);


        String string = new ObjectMapper().writeValueAsString(solve);

        System.out.println("string = " + string);
    }

    private static CouldBalancePlan generateDemoData() {
        List<Computer> computerList = new ArrayList<>();
        List<Processes> processesList = new ArrayList<>();


        computerList.add(Computer.builder().cpuPower(6).memoryCapacity(6).id(1).cost(1).build());
        computerList.add(Computer.builder().cpuPower(7).memoryCapacity(6).id(2).cost(1).build());
        computerList.add(Computer.builder().cpuPower(5).memoryCapacity(6).id(3).cost(1).build());
        computerList.add(Computer.builder().cpuPower(4).memoryCapacity(6).id(4).cost(1).build());
        //这里设置一台能够包揽所有进程的电脑,大家可以看下EasyScore和Constraint的区别,如果能够解决这个问题欢迎大家留言
        //computerList.add(Computer.builder().cpuPower(30).memoryCapacity(30).id(5).cost(1).build());


        processesList.add(Processes.builder().id(1).cpu(5).ram(5).build());
        processesList.add(Processes.builder().id(2).cpu(4).ram(3).build());
        processesList.add(Processes.builder().id(3).cpu(2).ram(3).build());
        processesList.add(Processes.builder().id(4).cpu(2).ram(1).build());


        return CouldBalancePlan.builder().computerList(computerList).processesList(processesList).build();
    }
}
五、最终解决方案
{
    "processesList":[
        {
            "id":1,
            "cpu":5,
            "ram":5,
            "computer":{
                "id":2,
                "cpuPower":7,
                "memoryCapacity":6,
                "networkCapacity":null,
                "cost":1
            }
        },
        {
            "id":2,
            "cpu":4,
            "ram":3,
            "computer":{
                "id":1,
                "cpuPower":6,
                "memoryCapacity":6,
                "networkCapacity":null,
                "cost":1
            }
        },
        {
            "id":3,
            "cpu":2,
            "ram":3,
            "computer":{
                "id":1,
                "cpuPower":6,
                "memoryCapacity":6,
                "networkCapacity":null,
                "cost":1
            }
        },
        {
            "id":4,
            "cpu":2,
            "ram":1,
            "computer":{
                "id":2,
                "cpuPower":7,
                "memoryCapacity":6,
                "networkCapacity":null,
                "cost":1
            }
        }
    ]
}

注:最重要的是建模思路,第二种建模思路我放在下一篇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值