【问题标题】:Optaplanner Drools performance is rather slowOptaplanner Drools 性能相当慢
【发布时间】:2019-04-22 09:56:21
【问题描述】:

为了可维护性、可读性和易用性,我将我们的分数计算器重写为 Drools,我发现它的性能仅比我们的 EasyScoreCalculator 稍微好一点,并且比我们的 IncrementalScoreCalculator 慢得多。 (切换到 Drools 的主要原因是未能在 IncrementalScoreCalculator 中实施新规则)。

这是一个比较:

请注意,Drools 仅比 Easy 快一点,而 Incremental 比两者都快约 8-10 倍。

我们有很多规则,请注意,虽然有些规则与增量规则差不多快或快,但有些规则确实很慢,可能会形成瓶颈。

这是一个快速规则的示例(~18-20 k calcs/sec)

rule "The volume of all orders can't exceed the volume of the van"
    when $vehicle : Vehicle($capacity : capacity)
      accumulate(
        Customer(
          vehicle == $vehicle,
          $demand : demand);
        $demandTotal: sum($demand);
        $demandTotal > $capacity
      )
    then
      scoreHolder.addHardConstraintMatch(kcontext, 2, -Math.round($demandTotal - $capacity));
end

这是一个非常慢的规则示例(~1k calcs/sec)

rule "A shipment cannot be serviced outside of the shift's service hours"
  when
    $c: TimeWindowedCustomer( vehicle != null, this.isServicable() == true);
  then
    scoreHolder.addHardConstraintMatch(kcontext, 0, -1);
end

还有一个非常慢的规则的例子:

rule "Total used volume in future shifts"
  when
    $shift: Shift(isCurrent() == false)
    $vehicle: TimeWindowedVehicle($shift == shift, $capacity: capacity)
    accumulate(
      Customer(
         vehicle == $vehicle,
         $demand : demand);
      $demandTotal: sum($demand);
      $demandTotal > 0
    )
  then
    int utilisedFutureShiftVolumePenalty = Params.App.Solver.Scoring.utilisedFutureShiftVolumePenalty;
    long score = - utilisedFutureShiftVolumePenalty * Math.round($demandTotal);
    scoreHolder.addSoftConstraintMatch(kcontext, 1, score);
end


我知道这些缓慢的规则会形成瓶颈并减慢整个 drools 分数计算,但我无法弄清楚为什么这些规则会成为瓶颈。我唯一能想到的是,我在慢速规则中调用了一个方法,而在快速规则中我没有。

这是为什么调用对象方法的规则比其他方法慢得多的原因吗?如果是,为什么以及我应该怎么做?

谢谢!

【问题讨论】:

    标签: drools optaplanner


    【解决方案1】:

    isServicable() 是做什么的?它的作用可能远不止return servicable;

    至于第二个慢规则,它是ShiftVehicle 的叉积的累加。积累有点慢(没有insertLogical那么慢,但仍然)。

    一旦我们发布它们,看看 ConstraintStreams 如何影响这些性能基准将会很有趣。

    【讨论】:

    • isServicable() 进行布尔检查 return dueTime <= customer.getReadyTime() || readyTime + MILLIS_PER_HOUR >= customer.getDueTime(); 我已经尝试将其置于规则中(尽管我不想这样做),但在性能方面并没有什么不同。关于第二个慢规则,它确实是ShiftVehicle 的叉积,但是Shift 只有一个实体,即isCurrent()==true,所以我认为它应该与首先是快速规则,性能明智。除非它在一个班次中的所有客户(大约 400 个实体)的每一步之后重新计算 (1/2)
    • 而第一个没有。 (每辆车约 14-15 位顾客)是这样吗? (2/2)
    • 那么这两种情况都很奇怪。 isServicable() impl 很好,它不做循环,所以它应该很快。如果确实有一个班次实例,则该交叉产品不应造成性能影响。在这一点上,只有深入的代码审查和一些广泛的基准测试才能有所帮助(我和我的同事只通过 Red Hat 服务做到这一点),但总而言之,每秒 3k 还不错。
    • 谢谢,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多