Drools 7.73.0中如何并行执行DRL规则的LHS逻辑?
解决Drools规则LHS逻辑并行执行的问题
核心误解:multithreadEvaluation的作用
你开启的multithreadEvaluation配置,只负责并行执行规则的RHS(then代码块),而非LHS(when部分)的匹配逻辑。Drools的Rete-OO算法本身是单线程处理模式匹配的,所以即使开启这个配置,LHS里的MyThreadUtil.sleep()依然会串行执行,这就是你调试时看不到LHS并行的原因。
针对LHS耗时操作的并行解决方案
方案1:预加载外部数据(推荐)
既然LHS的耗时来自REST API查询,最稳妥的方式是提前并行查询所有需要的外部数据,将结果作为事实插入KieSession,规则直接匹配内存中的事实即可,完全避免在LHS中执行阻塞操作。
示例代码:
// 并行调用所有需要的REST接口/耗时操作 List<CompletableFuture<Object>> futures = Arrays.asList( CompletableFuture.supplyAsync(() -> queryOrderAmount()), CompletableFuture.supplyAsync(() -> queryHistoryOrders()), // 其他需要的查询... ); // 等待所有查询完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 将查询结果插入KieSession futures.stream() .map(CompletableFuture::join) .forEach(session::insert); // 执行规则 session.fireAllRules(new RuleNameStartsWithAgendaFilter("multi_thread_"));
对应的DRL规则可以简化为直接匹配预加载的事实:
rule "multi_thread_1" no-loop true when $orderAmount : OrderAmount() // 匹配预加载的OrderAmount事实 then System.out.println($orderAmount.getValue()); end
方案2:使用Drools异步评估(Async Eval)
如果必须在LHS中处理耗时操作,可以使用Drools的async eval()语法(Drools 7及以上版本支持),将耗时逻辑包装为异步执行,同时需要配置自定义线程池。
修改后的DRL规则:
package multi.thread; import com.hp.util.MyThreadUtil; rule "multi_thread_1" no-loop true when $sleepTime1 : Integer() from async eval(MyThreadUtil.sleep()) then System.out.println($sleepTime1); end
同时需要在KieBase配置中指定异步线程池:
KieBaseConfiguration kbaseConfig = kieServices.newKieBaseConfiguration(); // 设置异步评估的线程池大小 kbaseConfig.setOption(AsyncEvaluationOption.get(true)); kbaseConfig.setOption(ThreadPoolOption.get(new ThreadPoolConfiguration() .setCorePoolSize(4) .setMaxPoolSize(8))); KieBase kieBase = kieContainer.newKieBase(kbaseConfig); KieSession session = kieBase.newKieSession();
方案3:多KieSession并行执行(规则完全独立场景)
如果你的100个规则完全独立(无共享事实、无规则间依赖),可以将规则分组,每组用独立的KieSession,通过线程池并行执行各组规则。
示例代码:
// 定义规则分组 List<List<String>> ruleGroups = Arrays.asList( Arrays.asList("multi_thread_1", "multi_thread_2"), Arrays.asList("multi_thread_3", "multi_thread_4") ); ExecutorService executor = Executors.newFixedThreadPool(2); // 并行执行每组规则 for (List<String> group : ruleGroups) { executor.submit(() -> { KieSession session = kieContainer.newKieSession(); session.fireAllRules(new RuleNameMatchesAgendaFilter(String.join("|", group))); session.dispose(); }); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES);
总结
- 优先选择预加载外部数据,这是最稳定且性能最优的方案,避免Drools内部异步逻辑的复杂性。
- 若必须在LHS处理,使用
async eval()并配置合适的线程池。 - 规则完全独立时,可以用多KieSession并行执行。
内容的提问来源于stack exchange,提问作者linhongpeng
相关产品推荐
相关产品推荐

